随意的世界 - 黑科技
type: channel
link: http://1.117.140.145/黑科技/
items: 时间API
items: LLM的有趣技术
items: 有趣的开源项目记录
items: 微分方程
items: 音频与信号的基础概念
items: 注意力就是你所需的一切
items: 动手深度学习-硬件对于训练的影响
items: 高效的serverless计算中的挑战与机遇
items: PID算法
items: 无聊netty写了个redis

时间API
type: item
date: 2026-05-08T10:45:00+08:00
description: 时间APITSCTSC（Time Stamp Counter，时间戳计数器）是现代 CPU 中一个非常底层的硬件计数器，用来记录自 CPU 上电以来经过的时钟周期数。TSC 本质上是一个 64 位寄存器，通常位于 CPU 内部，每当 CPU 时钟周期推进一次，它的值就 +1（在现代 CPU 中已经不完全等价于“每个核心周期”，但概念上仍是“高精度单调计数器”）。在 x86 架构中，可以通过指令读取：RDTSC（Read Time Stamp Counter）TSC 常用于性能分析，因为它的分辨率非常高（纳秒级甚至更细）。操作系统、数据库（比如 MySQL InnoDB）、高性能网络系统都会用 TSC 做：函数耗时统计lock contention 分析cache miss 成本分析TSC ≠ wall clock timevDSO优化vDSI是linux提供的一种机制，把一部分内核提供的只读系统调用映射到用户态的空间里，让用户态直接调用，而不需要陷入内核。vDSO = “内核提前帮你准备好的用户态函数库（但数据由内核更新）”典型函数包括：gettimeofdayclock_gettimetime传统路径：用户态函数调用 → syscall 指令 → CPU 切换到内核态 → 内核处理 → 返回用户态问题在于：syscall 有 上下文切换成本需要保存/恢复寄存器可能污染 CPU cache / pipeline高频时间查询会非常昂贵比如：一个高性能服务每秒可能调用 clock_gettime 上千万次具体方式：内核在进程地址空间映射一段“只读共享代码”用户态直接调用这些函数不发生 syscall数据仍由内核更新（比如时间）Linux CLOCK_MONOTONICCLOCK_MONOTONIC是Linux 提供的一种单调递增时钟，用于测量时间间隔，而不是表示当前真实时间。他的关键特性是：时间只会向前走不会因为系统时间被修改而改变。类型含义是否受系统时间影响CLOCK_REALTIME真实世界时间（Unix time）会（NTP、手动修改会跳变）CLOCK_MONOTONIC单调时间（从某个起点开始计时）不会CLOCK_MONOTONIC 的起点是：系统启动（boot）之后的某个未定义时间点注意：不等于 Unix epoch（1970）不可预测只保证单调递增他不能跨机器比较。也不能转换成unix时间戳。它不是时间而是时间差工具。

LLM的有趣技术
type: item
date: 2026-03-18T22:18:00+08:00
description: LLM的有趣技术https://www.bilibili.com/video/BV1gEcmzzE4P/语言模型的进化多模态大语言模型是如何将所有的感官，对齐到语言系统中的？这本质上属于多模态对齐（multimodal alignment）与表征学习（representation learning）的交叉问题。可以从结构层面+训练机制+对齐目标三个维度来精确理解。人类的感官数据在原始形态上完全是异构的，所以核心问题变成，如何把连续的信号映射到一恶搞可以被语言模型理解的符号空间。现代多模态大模型（如 GPT-4o、Gemini、Claude 等）通常采用如下结构：不同模态编码器 → 统一 embedding 空间 → LLM（语言核心）每种感官都有专属编码器，比如图像的Vit，音频的wav2vec，视频的时空tranformer，文本的token embedding。这些编码器的目标都是抓成一个高维语义向量。那么如何对其到共享语义空间？对比学习对比学习：Contrastive learning 代表作为CLIP。训练目标：图像embedding=描述该图像的文本。即最大化：正样本（匹配图文）的相似度负样本（不匹配）的距离结果图像和语言落在同一个语义空间中跨模态生成Generative Alignment图像 → 文本（captioning）音频 → 文本（ASR）视频 → 文本（描述）训练方式输入：图像 embedding目标：生成对应文本 token让 LLM 学会“用语言解释感官”联合训练直接训练一个模型处理：[图像 tokens] + [文本 tokens] → 预测下一个 token把非语言模态“token化”（tokenization of modalities）语义一致性最终目标不是“数据形式一致”，而是：不同模态表达相同“意义”时，其内部表示接近一张猫的图片“a cat sitting on a sofa”在 embedding 空间中应接近为什么语言成为“中心模态”？语言有几个决定性优势可以表达复杂结构：时间因果抽象概念标注成本最低：图像/音频的语义通常通过语言标注获得LLM 的核心能力：chain-of-thoughtplanningabstraction都发生在语言空间。语言不是被对齐的对象，而是“语义坐标系”所有感官数据都被投影到这个坐标系中。换句话说：图像 ≠ 变成文字图像 → 映射到“可以用语言解释的语义空间”思维连chain-of+thought。本质是让模型在给出最终答案之前，显式或隐式的生成中间推理步骤，从而提升复杂任务的正确率。传统语言模型直接输出答案，COT是在输出和最终答案中增加了思考步骤。模型被引导像人一样一步步想。可以将一个复杂的问题，拆成多个简单的子问题。在训练或推理是。没有CoT只有最终loss，有CoT：每一步都有结构化的模式。本质上相当于在token级别上引入推理轨迹约束。CoT 提示过程是一种最近开发的提示方法，它鼓励大语言模型解释其推理过程。思维链的主要思想是通过向大语言模型展示一些少量的 exapmles，在样例中解释推理过程，大语言模型在回答提示时也会显示推理过程。这种推理的解释往往会引导出更准确的结果。零样本思维链（Zero Shot Chain of Thought，Zero-shot-CoT）提示过程是对 CoT prompting 的后续研究，引入了一种非常简单的零样本提示。他们发现，通过在问题的结尾附加“Let's think step by step”这几个词，大语言模型能够生成一个回答问题的思维链。从这个思维链中，他们能够提取更准确的答案。外部工具ReAct 和 Toolformer 是两种典型的“让模型使用工具/外部能力”的方法论，但它们的设计哲学和实现路径差异很大ReActReAct = 推理（Reasoning）+ 行动（Acting）交替进行模型在推理过程中，不只是“想”，还会：显式生成思考链（Thought）决定调用工具（Action）接收工具返回结果（Observation）再继续推理本质：把推理过程外显，并嵌入工具调用显式推理链（Chain-of-Thought）类似 CoT，但更进一步推理过程中可以“打断去查资料”动态工具调用工具使用是 runtime 决策不需要提前训练工具调用能力强交互性适合：多步推理（multi-hop QA）agent系统复杂决策任务ToolformerToolformer = 让模型自己学会什么时候调用工具和 ReAct 最大区别：ReAct：靠 prompt 引导Toolformer：靠训练学出来Toolformer 做了三件关键事：自监督生成工具调用数据给模型少量 seed examples，然后：模型自动：在文…

有趣的开源项目记录
type: item
date: 2026-01-04T11:04:02+08:00
description: 有趣的开源项目记录分类整理1. 开发与编程工具Go-blueprint - 命令行交互式创建和初始化Go项目，支持网页端选择Pake - 用Rust开发的工具，可将网页打包成macOS、Windows、Linux支持的桌面客户端应用，封装体积比Electron小20倍manim - 3Blue1Brown作者开发的强大数学动画引擎，专为数学和科学可视化设计，推荐使用社区版manimCEDeepface - 轻量级Python人脸识别工具，支持年龄、性别、情绪、种族识别，准确率超过人类RealtimeSTT - 开源实时语音转文本库，采用流式处理技术，延迟极低，支持模型量化Amphion - 开源音频、音乐和语音生成工具包，支持TTS、SVC、TTA、VC等功能Skyvern - 基于视觉理解的网页自动化工具，摆脱传统DOM依赖，采用多智能体协作架构index-tts2 - 文本转语音工具2. 数据库与数据处理Teable - 现代化的无代码数据库与数据协作平台，基于PostgreSQL构建，类Airtable界面DiceDB - 开源高性能内存数据库，作为Redis替代品，适合高速缓存和实时系统Docling - 文档解析工具，支持导出markdown和JSON，支持OCRGitdiagram - 将GitHub仓库转换为交互式架构图3. 系统工具与操作系统PowerToys - Windows系统增强工具，包含快速启动器、图片批量处理、拾色器、文本提取器等Ventoy - 多系统启动U盘制作工具Windows via Docker - 从Docker安装Windows，在Linux中通过浏览器访问，支持Win7-11WebVM - 在网页端运行的Linux虚拟机，甚至可以运行可执行文件Jellyfinweb - 媒体服务器Web界面4. 网络与文件共享LocalSend - 本地网络安全文件共享工具，无需互联网连接FilePizza - 基于WebRTC的点对点文件传输，文件直接从发送者浏览器传到接收者浏览器File-transfer-go - Go语言实现的文件传输工具Netbird - 点对点VPN/内网穿透工具AList - 聚合网盘工具Linux Mirrors - Linux镜像源管理工具5. 监控与管理Infisical - 开源密钥管理工具，类似HashiCorp Vault，支持微服务架构Beszel - 轻量级服务器监控平台，支持Docker容器监控，资源占用低XPipe - 终端连接工具Openlist - 开源列表管理工具6. 安全与渗透测试Hacking tool - 一体化黑客工具箱，包含各类漏洞扫描和攻击工具Sherlock - 社交媒体账号搜索工具，支持400多个网站查询7. 人工智能与分布式计算EXO - 分布式AI计算集群框架，允许连接日常设备形成AI计算集群Pansou - 开源搜索引擎Weepwiki - 知识库/wiki系统项目详细记录开发与编程工具Go-blueprint通过命令行交互式的创建和初始化Go的项目。也可以在网页里直接选择。Pake一个用Rust开发的小工具，可以把网页打包成macOS、Windows、Linux三种系统支持的桌面客户端应用。Pake的封装比Electron的封装小20倍。manim3Blue1Brown的作者开发的强大动画引擎。专为数学和可视化科学设计。能生成高质量的数学动画。推荐使用manim和manimCE（社区版），因为会更稳定。DeepfaceDeepface是一个轻量级的Python人脸识别工具。支持年龄、性别、情绪、种族识别。它是混合面部识别框架，集成了多种识别模型。准确率已经超过了人类。RealtimeSTT是一个开源的实时语音转文本（Speech-to-Text，STT）库，专为低延迟应用设计。该项目由KoljaB开发，采用Python语言编写，能够将语音数据实时转换为文本，适用于语音助手、实时字幕生成、会议记录等多种场景。采用流式处理技术，在语音输入的同时实时输出转写结果，延迟极低。基础模型（tiny）运行时内存占用约400MB，大型模型（large-v2）在GPU环境下显存占用约4.2GB。通过INT8量化技术，模型内存占用可减少75%。AmphionAmphion是一个由上海人工智能实验室、香港中文大学（深圳）数据科学学院和深圳市大数据研究院联合开发的开源音频、音乐和语音生成工具包。该项目于2023年12月开源，旨在支持可重复的研究，帮助初级研究人员和工程师快速进入音频生成领域。它支持TTS、SVC、TTA、VC等功能。SkyvernSkyvern的最大突破在于摆脱了传统自动化工具对DOM结构和XPath选择器的依赖。传统工具如Se…

微分方程
type: item
date: 2024-10-09T14:51:05+08:00
description: 微分方程https://www.bilibili.com/video/BV1tb411G72z从牛顿时期人们就意识到，所有的物理定律都可以当描述相对变化量比绝对量更容易时，微分方程就经常被用到了。比如为什么它在某个时间是某个特定值更容易。这些方程有俩中不同的形式常微分方程：（ODE）函数的自变量只有一个 通常是时间。和偏微分方程：函数有多个自变量（可以想象成一个随着时间变化的一个连续体。就像固体中任意一点的温度。或者空间中任意一点的流体速度。）常微分方程常微分方程只涉及时间变换的有限集合。也不需要时间，这个时间可以是任何事物。想象一下抛向空中物体的轨迹，地表的重力给了物体向下的速度。这个加速度约为$-9.8m\frac{m/s}{s}$这些速度矢量每秒增加9.8m/s的向下分量。我们使用g来替代这个常量。（简单来说就是每秒下落的距离。）把y坐标看成时间函数，它的导数是加速度的垂直分量。再取一次导数就是加速度的垂直分量。我们的微分方程就是y的二阶导数也就是-g是一个常量。这个问题我们可以通过积分来解决，本质上是一个逆运算的过程。根据有关变化率的信息，最后计算得出函数是什么。如果计算一个更加复杂一点的问题时，这个引力就不一定是一个常量了。如果有俩个物体其中一个物体的受力方向是指向另一个物体。在微分方程中，面对的问题往往是找到一个函数，其导数（以及高阶导数）也是由这个函数本身定义的。在物理学中，二阶微分方程是最常见的。也就是表达式中最高阶倒数是二阶导数。高阶微分方程是包含三阶导数，四阶导数或更高阶导数的微分方程。在某种意义上，你要找到无穷多数，每个数对应一个时间T。单它们满足一个很具体的约束条件，要和自己的变化率以及变化率的变化率交织在一起。$360^∘=2\pi弧度$。也就是说一个完整圆的弧度为$2\pi$。我们用振幅所对的弧长x来表示它的位置。$\theta$是角度，L是摆长。若$\theta$角是用弧度制表示的，x可以写为$x=L\times \theta$但由于单摆限制了这个系统的运动，我们需要关注加速度在运动方向的分量了。其中图中这个夹角也为$\theta$这里不再进行证明所以这个叫在蓝色运动方向上的分量为$-g*sin(\theta)$。而粉色为$-g*cos(\theta)$。我们规定单摆在右边时$\theta$为正，左边时为负数。所以x的二阶导数，即加速度是$-g*sin(\theta)$。当$\theta$为0时sin(0)为0，所以这时候在运动的方向没有加速度。当$\theta$是90度的时候（也就是$\frac{\pi}{2}$）这时候加速度和自由落地是一样的。因为$x=L\times \theta$，所以$\theta$的二阶导数为$-\frac{g}{L}sin(\theta)$为了更真实一点，我们考虑空气阻力。也就是$\ddot\theta=-u\dot\theta-\frac{g}{L}sin(\theta) $。假定空气阻力大小和速度成正比。也就是$$ $\ddot\theta=-u\dot\theta(t)-\frac{g}{L}sin(\theta(t)) $$这个u代表了单摆的空气阻力，摩擦系数等。也决定了单摆损失能量的速度。式子中正弦函数的存在，恰好是现实中单摆不会以正弦波形式摆动的原因。我们可以发现微分方程很那解。没有任何已知的方法可以精确求解$\theta(t)$是多少。所以在学习微分方程时，我们常跳过求解过程，因为它根本无法得到。而是但从方程进建立理解和计算。单摆的状态可以用俩个数字表示，角度和角速度。(分别为横轴和纵轴。)可以在不影响其中一个值的情况下改变另一个值。但是加速度值关于这俩个值的函数。如果已知初始角度和角速度，就足以预测随着时间推移这个系统是如何演变的。通过这个空间，我们可以将微分方程可视化为向量场。假设单摆的状态是向量$[\theta(t),\theta'(t)]$。对于这个向量求导就可以得到它的变化率。也就是在这个图像中变换的趋势速度和大小方向。$$ \frac{d}{dt}\begin{bmatrix}\theta(t)\\\dot{\theta}(t)\end{bmatrix}=\begin{bmatrix}\dot{\theta}(t)\\\ddot{\theta}(t)\end{bmatrix} $$对于空间内所有店做这个操作，就可以看出任意一个位置的变化趋势事实上我们已经把一个二阶方程分解为俩个一阶方程。（一阶常微分方程组System of tow first order）任何常微分方程系统都能用这样的向量图来表示。所以通过构造向量图来理解他们是非常常见的。一般情况下系统都有很多个维度。在数学上我们把这个叫做相空间（phase space），来指代描述运动系统…

音频与信号的基础概念
type: item
date: 2024-09-08T11:42:19+08:00
description: 音频与信号的基础概念傅里叶级数Fourier Series (thefouriertransform.com)傅里叶级数将周期函数分解到正弦曲线的函数中。它是周期函数的傅里叶变换。为了开始分析傅里叶级数，让我们定义周期函数。一个周期为T的函数如果对下列条件成立$$ f(t+T)=f(t) $$简单来说，这以为这周期为T的函数将会在T秒时出现和现在一样的值。不管你什么时候观察这个函数。注意一个周期为T的函数，也是周期为2T的函数。所以基本的周期是T的值值中最小的可能性让以上等式依然可以成立。来看图1图1的方型波基本的周期为T。现在让我们来定义傅里叶级数。周期为T的傅里叶级数，是正弦函数的无穷和（cosine 和 sine），每个频率都是1/T的整数倍(基本周期的倒数)。傅里叶级数也包括了常熟，因此被写作：$$ \begin{gathered} g(t) =a_{0}+\sum_{m=1}^{\infty}a_{m}\cos\biggl(\frac{2\pi mt}{T}\biggr)+\sum_{n=1}^{\infty}b_{n}\sin\biggl(\frac{2\pi nt}{T}\biggr) \\ =\sum_{m=0}^{\infty}a_{m}\cos\biggl(\frac{2\pi mt}{T}\biggr)+\sum_{n=1}^{\infty}b_{n}\sin\biggl(\frac{2\pi nt}{T}\biggr) \end{gathered} $$其中的常数$a_m,b_n$是傅里叶级数的系数。它决定了乜咯正弦曲线的权重。现在的问题是：对于任意的周期函数f(t)，我们能用周期为基本周期的整数倍的简单正弦波来多么接近地近似这个函数？也就是，对于给定的周期函数f(t),函数g(t)和f(t)由多接近。这个结果是数学中最棒的结论之一，即：我们可以精确的近似f(t)，只要f(t)是连续且光滑。现实中，所有的函数都是连续和光滑的。所以对于时间中的工程师或者物理学家，所有的周期性函数可以精准的通过傅里叶级数来进行表示。这是一个很棒的结果傅里叶变换正弦波正弦曲线或正弦波（Sinusoid／Sine wave）是一种来自数学三角函数中的正弦比例的曲线。也是模拟信号的代表，与代表数字信号的方波相对。正弦曲线的形状就像完美的海上波浪，以三角函数正弦比例改变而形成。标准的纯正弦函数公式为$$ y=sin(x) $$sin(x) 为正弦函数。而一般应用的正弦曲线公式为$$ y=A\cdot\sin(\omega t+\theta) $$A 为波幅（纵轴）， ω 为角频率， t 为时间（横轴），θ为初始相位(t=0时的)。以下的公式则拥有全部的可用参数.$$ y=A\cdot\sin(kx-\omega t-\theta)+D $$k 为波数（周期密度）， D 为（直流）偏移量（y轴高低）。因为cos⁡x=sin⁡(x+π2)，$\displaystyle \cos {x}=\sin(x+{\frac {\pi }{2}})$所以余弦波也是正弦波。基本事实上时姐上所有的函数都可以被描述成为一个波形，是一个时间空间或者其他变量的函数。例如，声波，电磁场，山的高度与位置的关系，驻波比与频率的关系图，你最喜欢的股票价格与时间的关系等。傅里叶变换给了我们一种独特的强有力的能力来观察这些波形。基于这样一个事实-宇宙的基本秘密之一：所有的波形无论你在宇宙中如何描述或者观察，它们只是不同频率的简单正弦曲线的和。正如我们看到的一样这个事实很酷。傅里叶变换分解了波形：任何真实世界的波形变为正弦曲线。即，傅里叶变换给出了一种表示波形的方法让我们将图1中的曲线分解为建筑块（或者成分的频率）。这个分解可以用傅里叶变换来完成（或者周期波形的傅里叶级数），就像我们看到的一样。第一个曲线为正弦曲线其周期为T=6.28(2pi)，幅值0.3的正弦波如图1所示。图1：一个基本频率（左）和原来的原始波形（右）的比较第二个频率的周期是第一个的一半（频率的俩倍）。第二个组成部分展示在图2左侧，加上俩个频率域原始波形的和。图2：第二个原始频率（左）和源波形与前俩个频率组合的比较。我们可以看到前俩个频率的和开始长得像源波形。最后我们加入4个频率分量得到原始波形。傅里叶变换是基本的工具像我们展示了如何结构波形成为几个正弦函数的组成部分。它在很多领域都用应用，帮助我们理解宇宙，这让实践工程师或科学家的生活变得更容易。梅尔频谱Understanding the Mel Spectrogram | by Leland Roberts | Analytics Vidhya | Medium信号信号是一定数量随着时间的变化。对于音频变化的量是空气的压力。我们如何以数字的方式补货…

注意力就是你所需的一切
type: item
date: 2024-09-02T12:25:00+08:00
description: 注意力就是你所需的一切Attention is All you Need (acm.org)概要主要序列转换模型是基于复杂的循环或者卷积神经网络的，它包括了编码器和解码器。我们提出了一个新的简单网络架构，Transformer，基于单一的注意力机制，完全不适用递归和卷积。实验在俩个机器翻译任务上展示了这些模型的优秀的品质，同时更加并行化只需要更少的训练时间。我们的模型在WMT2014英语生产翻译任务上达到了28.4的BLEU，比现有最佳的结果（包括组合）提高了2BLEU。在一个WMT 2014英语-发育的翻译任务重，在8个GPU上训练了3.5天之后我们模型简历了新的简单模型，最高的BLEU分数，从文献中得到最好模型的一小部分训练成本。1 介绍在实践中循环神经网络，长短期记忆网络和门控循环单元网络，已经在序列模型和如同语言模型与机器翻译模型的传到问题中，被牢牢确立为最先进的方法。此后许多努力仍在继续以突破循环语言模型和编码器解码器架构的边界。循环模型通常沿着输入和输出序列的符号位置来进行计算分解。将位置与计算时间中的步骤对其，它生成隐藏状态序列$h_t$，作为上一个隐藏层状态$h_{t-1}$和位置的输入函数。这个内在的序列在训练中排除了并行性，并行性在长序列上很重要，由于内存约束限制了跨样例的批处理。最近的工作通过因式分解的技巧和条件计算得到了显著的提升，同时也提升了模型在之后例子中的性能。然而基本的顺序计算限制还是存在。注意力机制已经成为了引人注目的序列建模和多变任务中的转换模型的重要组成部分，允许模型对以来进行建模而不管它们的在输入或输出序列中的距离。然而除了少数情况外，这样的attention机制被用来与RNN一起使用。在这个工作中我们提出了Transformer，一个避免了循环和而是以来整个注意力机制去绘制在输入输出中的整个依赖。Transformer允许显著的更多并行，在P100GPU上训练了12个小时后，可以让翻译质量达到一个新的境界。2 背景减少顺序计算的目标也构成了Extended Neural GPU，ByteNet，ConvS2S的基础，所有这些都使用卷积神经网络作为基本构建块，并行计算所有输入输出位置的隐藏表示。在这个模型中，将来自俩个任意输入或输出位置的信号联系起来所需的操作数量随着位置之间的距离而增加，对于ConvS2S是线性的，对于ByteNet是对数的。这让学习距离和位置之间的关系变得很难。在Transformer中这被简化成为了一个常量超操作，尽管关于平均注意力加权位置降低了有效的决议，我们使用多头注意力抵消了影响，如3.2章所述。一些时候，自注意力机制被叫做内部注意力，关联了一个序列中的相关的不同的电，以计算序列的表示。自注意力机制成功的备用在多个任务上其中包括：阅读理解，摘要概要，文字循环和学习与任务无关的句子的表示。端到端的内存网络是基于循环注意力机制的而不是序列排列的重复，已经展示了在简单问题回答和语言建模问题上的良好性能。然而据我们所知，Transformer是第一个完全依赖注意力机制模型，以计算输入和输出而不适用序列排列的RNN或者卷积。在之后的章节中，我们将描述Transformer，促进自注意力机制和讨论相对于其他模型的优势。3 模型架构最局竞争的神经序列转换模型有一个解码器和编码器结构。其中，解码器映射用符号表示的输入序列($x_1,...,x_n$)到连续的表示序列z=($z_1,...,z_n$)中，给定z，解码器生成输出序列($y_1,..,y_m$)符号，一次一个元素。在每一步模型都是自回归的，在生成下一个符号时，使用生先前生成的符号作为附加输入。Tansformer遵循寻使用堆叠的自我关注和点方向，对编码层和解码层进行全链接，分别展示在图1左右俩边。3.1编码器和解码器堆叠编码器：编码器是由N为6的相等的层堆叠而成的。每个层有俩个子层。 第一个多头自注意力机制，第二个是简单的positionwise全链接前馈网络。我们使用残差链接环绕着俩层，然后是层归一化。每一个子层的输出都是LayerNorm(x + Sublayer(x))，其中Sublayer(x)是一个实现了子层自身的函数。以方便这些残差连接，在模型中所有的子层和嵌入层产生维度$d_{model}=512$的输出解码器：解码器也是由N为6的相等的层堆叠而成的。除了在每个编码器层添加俩个子层之外，解码器插入了第三个子层，它对编码器栈执行多头注意力。类似编码器，我们使用残差链接包围每个子层，然后是归一化层。我们也改进了在decoder栈中的自注意力子层以防止位置关注后续位置。这种遮蔽，结合了一个事实：输出嵌入偏移一个位置，确保对于位置i的预测只能依赖位置小于i的已知输出。3.2 注意力注意力函数可以表述将一组查询…

动手深度学习-硬件对于训练的影响
type: item
date: 2024-07-30T20:12:48+08:00
description: 动手深度学习-硬件对于训练的影响CPU训练在计算a+b的数据需要准备a和bl1访问延迟是0.5nsl2访问延迟是7ns主内存访问延迟100ns(200xl1)提升空间和时间的内存本地性时间：重用数据使得保持他们在缓存中空间：按需读写数据可以使得预读取所以一个矩阵如果按列存储，访问一行会比访问一列要快GPU每个绿点是一个小的处理器(这是泰坦x)cpu和核心数在6/64-2k/4k每秒计算的浮点数就是核的数量乘以主频。内存带宽显卡也是十倍甚至上百倍于GPU，cpu为30GB-100GB，而GPU为400GB-1TB但是CPU控制流强于GPU如何提升GPU利用率并行：使用数千个线程（也叫流处理器）内存本地访问性：哈运存更小，架构耿凯但你少用控制语句：支持有限，同步开销很大不要频繁在CPU和GPU之间传输数据CPU高性能使用C++，编译器成熟GPU NVIDIA上用CUDA，OpenCL，质量取决于硬件厂商单机多卡并行一台机器能装1-16个GPU在训练和预测时，将一个小批量计算切分到多个GPU上来达到加速的目的常用的切分方案有数据并行：将小批量分成n块，每个GPU拿到完整的参数计算这一块数据的梯度，性能通常更好。模型并行：将模型分成n块，每个GPU拿到一块模型计算它的前向结果，通常用于模型大道单GPU放不下通道并行（数据+模型并行）需要模型并行的场景是一张卡放不下模型。多GPU代码实现从0开始实现多GPU训练import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2l scale = 0.01 W1 = torch.randn(size=(20, 1, 3, 3)) * scale b1 = torch.zeros(20) W2 = torch.randn(size=(50, 20, 5, 5)) * scale b2 = torch.zeros(50) W3 = torch.randn(size=(800, 128)) * scale b3 = torch.zeros(128) W4 = torch.randn(size=(128, 10)) * scale b4 = torch.zeros(10) params = [W1, b1, W2, b2, W3, b3, W4, b4] # 定义模型 def lenet(X, params): h1_conv = F.conv2d(input=X, weight=params[0], bias=params[1]) h1_activation = F.relu(h1_conv) h1 = F.avg_pool2d(input=h1_activation, kernel_size=(2, 2), stride=(2, 2)) h2_conv = F.conv2d(input=h1, weight=params[2], bias=params[3]) h2_activation = F.relu(h2_conv) h2 = F.avg_pool2d(input=h2_activation, kernel_size=(2, 2), stride=(2, 2)) h2 = h2.reshape(h2.shape[0], -1) h3_linear = torch.mm(h2, params[4]) + params[5] h3 = F.relu(h3_linear) y_hat = torch.mm(h3, params[6]) + params[7] return y_hat # 交叉熵损失函数 loss = nn.CrossEntropyLoss(reduction='none') def get_params(params, device): new_params = [p.to(device) for p in params] for p in new_params: p.requires_grad_() return new_params new_params = get_params(params, d2l.try_gpu(0)) print('b1 权重:', new_params[1]) print('b1 梯度:', new_params[1].grad) def allreduce(data): for i in range(1, len(data)): data[0][:] += data[i].to(data[0].device) for i in range(1, len(data)): data[i][:] = data[0].to…

高效的serverless计算中的挑战与机遇
type: item
date: 2024-05-30T15:53:27+08:00
description: 高效的serverless计算中的挑战与机遇论文原文Sci-Hub | Challenges and Opportunities for Efficient Serverless Computing at the Edge. 2019 38th Symposium on Reliable Distributed Systems (SRDS) | 10.1109/SRDS47363.2019.00036概述无服务计算框架允许用户在不处理操作问题的情况下执行小型应用程序（专心特定的任务），如服务配置，资源管理和负载增高情下的资源缩放。serverless计算最初出现云计算框架下，但是它可能与物联网完美匹配在边缘计算的数据处理方面。但是现在的serverless方案是基于VM和容器的，他对于边缘计算的操作效率和弹性伸缩来说太重了（更大的内存占用和更高的函数调用时间）。此外，更多新奇的IOT应用包含低延迟数据处理和准实时的响应。这使得基于云的serverless方案不合适。不久前wasm作为一种以原生速度运行serverless应用的备选方案被提出了，同时具备小内存占用和最优的执行时间。在这个文章中，我们讨论一些现在serverless的环境，它们的设计详情，未解决的性能挑战在边缘进行高效的无服务管理。我们概述了我们的无服务框架，叫做aWsm，基于webassmbly的方式，讨论机会使用根据aWsm设计，包含功能剖析，SLO（service level objective）驱动的用户功能性管理。最后我们给出了初步评估，以平均启动时间为特征的性能(12μs to 30μs)和用于用作函数的MiBench微基准标记的子集的经济内存占用（从10s到100s的kB）。引言工业物联网的激增和下一代技术（自动驾驶，智能城市，智能电网等）使越来越多的新应用程序成为可能。它们包含了数据处理系统在新性能特性于低执行延迟和高质量服务（Qos）想象一个智能城市自动化街道和红绿灯，他感知交通流量和聚焦于优化整个系统的效率，也明智的响应医疗和消防部门的紧急请求，以满足他们的需求和服务水平目标（Service level Objectives SLOs）。想象一个通信汽车和相关数据服务的世界，可以提醒驾驶员危险道路通知：再你前面的录上有黑冰这俩个应用程序需要从多样的设备源处理大量新的数据在几乎实时的方式支持所需的功能。实时性能是许多工业和企业中的控制和检测所预期的。一些方案需要在10ms内响应。如果数据分析和控制逻辑实现在云端，这样的系统无法满足实时服务的要求。时间敏感的应用有车机系统，根本无法依赖和云端的连接。这样的程序必须在设备上本地的运行。多种最近的趋势和相关的技术挑战激发了我们的兴趣：优化serverless的边缘计算。尽管云计算为以人类感知速度设计的应用程序提供了一个很好的解决方案，他变得不适合对延迟敏感的IOT应用上它们依赖速度，自动化决策无需人工参与。为了满足工作负载的性能需求，我们必须提供一个新方式更接近源头的去处理这些数据。换而言之，在边缘提供云计算。此外，这种方法将有助于支持数据安全和隐私问题。没有人希望他们的数据被破坏，当数据在云和设备不断转移时，这种风险更高。用户对于隐私和数据控制的要求越来越高，边缘计算能够解决这些多重问题。关键的区别和挑战，当边缘计算和云计算进行比较时，边缘表示资源受限的环境因此，边缘资源需要谨慎共享在多租户和高效管理，以支持所需的物联网数据处理功能。serverless计算，也成为fuction-as-a-service（Fass）函数即服务。提供了新的执行模型，这使得用户运行他们的代码。不用担心操作问题。这种方式，用户不用担心的从多个参与的服务配置和资源管理。serverless应用亦在事件驱动和无状态。比如Fass可以实例化去执行预定义的函数和再他们完成的时候终止执行。在商业化系统中，用户按调用次数计费，不支付未使用或闲置资源的费用。通过无限的云端资源。serverless计算代表了一种效用计算形式，通过可用的按需计算资源访问弹性伸缩。自亚马逊lambda提供以来，大量主要的云提供商提供了serverless平台，包括谷歌云函数，微软Azure函数和IBM云函数。现在的serverless框架主机函数实例在短周期虚拟机或容器，它支持应用处理隔离和资源提供。这些框架有重中在边缘计算系统，并且在提供低延迟方面效率低下，尤其是函数第一次实例化时。例如从aws lambda的125毫秒到microsoft Azure functions的一秒。为了获得更好的效率，这些平台缓存和重用容器在多个方法在给定的时间窗口内调用。例如五分钟，一些用户发送认为请求以避免容器关闭。在边缘环境下，使用长就存活或者过度供应的容器或者虚拟机会…

PID算法
type: item
date: 2024-01-12T09:28:00+08:00
description: PID算法PID控制算法原理（抛弃公式，从本质上真正理解PID控制） - 知乎 (zhihu.com)简介期望值是什么，与控制器没有关系，而是与物理对象有关。更直接的原因是你使用了这个物理量而做的反馈。期望值需要与反馈做差，所以期望值采用有了意义。期望值是什么取决于反馈值是什么。PID控制应该算是非常广泛的控制算法了。小的控制一个元件的温度，大到控制无人机的飞行姿态和飞行速度等，都可以使用PID控制。我们从原理上来理解PID控制（proportion integration differention）其实就是指比例，积分，微分控制。先把图片和公式摆出来，看不懂没关系。比例控制算法我们先说PID中最简单的比例控制，抛开其他两个不谈。还是用一个经典的例子吧。假设我有一个水缸，最终的控制目的是要保证水缸里的水位永远的维持在1米的高度。假设初始时刻，水缸里的水位是0.2米，那么当前时刻的水位和目标水位之间是存在一个误差的error，且error为0.8.这个时候，假设旁边站着一个人，这个人通过往缸里加水的方式来控制水位。如果单纯的用比例控制算法，就是指加入的水量u和误差error是成正比的。即u=kp*error假设kp取0.5（KP代表比例增益Proportional Gain）那么t=1时（表示第一次加水，也就是第一次对系统施加控制），那么u=0.5*0.8=0.4，所以这一次加入的水量会在使水位上升在0.2的基础上上升0.4，达到0.6.接着，t=2时刻（第2次施加控制），当前水位是0.6，所以error是0.4。u=0.5*0.4=0.2，会使水位再次上升0.2，达到0.8.如此这么循环下去，就是比例控制算法的运行方法。可以看到，最终水位会达到我们需要的1米。但是，单单比例控制存在着一些不足，其中一点就是稳态误差！像上述的例子，根据kp取值不同，系统最后都会达到1米，只不过kp大了到达的快，kp小了到达的慢一些。不会有稳态误差。但是，考虑另外一种情况，假设这个水缸在加水的过程中，存在漏水的情况，假设每次加水的过程，都会漏掉0.1米高度的水。仍然假设kp取0.5，那么会存在着某种情况，假设经过几次加水，水缸中的水位到0.8时，水位将不会再变换！！！因为，水位为0.8，则误差error=0.2. 所以每次往水缸中加水的量为u=0.5*0.2=0.1.同时，每次加水，缸里又会流出去0.1米的水！！！加入的水和流出的水相抵消，水位将不再变化！！也就是说，我的目标是1米，但是最后系统达到0.8米的水位就不再变化了，且系统已经达到稳定。由此产生的误差就是稳态误差了。（在实际情况中，这种类似水缸漏水的情况往往更加常见，比如控制汽车运动，摩擦阻力就相当于是“漏水”，控制机械臂、无人机的飞行，各类阻力和消耗都可以理解为本例中的“漏水”）所以，单独的比例控制，在很多时候并不能满足要求。积分控制算法还是用上面的例子，如果仅仅用比例，可以发现存在稳态误差，最后的水位就卡在0.8了。于是在控制中，我们再引入了一个分量，该分量和误差的积分是正比关系。所以+积分控制算法为u=kp*error+ ki∗∫ error还是用上面的例子来说明，第一次的误差error是0.8，第二次的误差是0.4，至此，误差的积分（离散情况下积分其实就是做累加），∫error=0.8+0.4=1.2, 。这个时候的控制量，除了比例那一部分，还有一部分就是一个系数ki乘以这个积分项。由于这个积分项会讲前面若干次的误差进行累计，所以可以很好的消除稳态误差（假设在仅有比例项的情况下，系统卡在稳态误差了，即上例中的0.8，由于加入了积分项的存在，会让输入增大，从而使得水缸的水位可以大于0.8，渐渐到达目标的1.0.）这就是积分项的作用。微分控制算法换一个另外的例子，考虑刹车情况。平稳的驾驶车辆，当发现前面有红灯时，为了使得行车平稳，基本上提前几十米就放松油门并踩刹车了。当车辆离停车线非常近的时候，则使劲踩刹车，使车辆停下来。整个过程可以看做一个加入微分的控制策略。.微分，说白了在离散情况下，就是error的差值，就是t时刻和t-1时刻error的差，即u=kd*（error（t）-error（t-1）），其中的kd是一个系数项。可以看到，在刹车过程中，因为error是越来越小的，所以这个微分控制项一定是负数，在控制中加入一个负数项，他存在的作用就是为了防止汽车由于刹车不及时而闯过了线。从常识上可以理解，越是靠近停车线，越是应该注意踩刹车，不能让车过线，所以这个微分项的作用，就可以理解为刹车，当车离停车线很近并且车速还很快时，这个微分项的绝对值（实际上是一个负数）就会很大，从而表示应该用力踩刹车才能让车停下来。切换到上面给水缸加水的例子，就是当发现水缸里的水快要接近1的时候，加入微分项，可…

无聊netty写了个redis
type: item
date: 2023-12-08T16:02:00+08:00
description: 无聊netty写了个redis首先是redis的服务端,除了访问的进程外还会存储各个进程发上来的一个id方便进行下发这是速度测试package org.example.netty.redis; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.string.LineEncoder; import io.netty.handler.codec.string.LineSeparator; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.concurrent.LinkedBlockingDeque; /** * @Author: suiyi * @Date: 2023/11/30 20:21 */ public class NettyServerRedis { static HashMap<String, String> map = new HashMap<>(); static LinkedBlockingDeque<Action> workQueue = new LinkedBlockingDeque<>(); public static void main(String[] args) throws InterruptedException { new Thread(() -> { try { consumerWorkQueue(); } catch (InterruptedException e) { throw new RuntimeException(e); } }).start(); ServerBootstrap serverBootstrap = new ServerBootstrap(); NioEventLoopGroup boos = new NioEventLoopGroup(); NioEventLoopGroup worker = new NioEventLoopGroup(); serverBootstrap .childOption(ChannelOption.SO_KEEPALIVE, true) .group(boos, worker) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<NioSocketChannel>() { protected void initChannel(NioSocketChannel ch) { ByteBuf buffer = Unpooled.copiedBuffer("\0".getBytes()); ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG)); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(8192, buffer)); ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new StringEncoder()); ch.pipeline().addLast(new LineEncoder(new LineSeparator("\0"), Stan…