图神经网络(GNN)入门|文章笔记与要点整理

此笔记是在阅读<<A Gentle Introduction to Graph Neural Networks>>的过程中写下的 阅读文章的同时观看了B站UP主 跟李沐学AI 的视频 零基础多图详解图神经网络(GNN/GCN)【论文精读】 文章链接 :A Gentle Introduction to Graph Neural Networks 视频链接 :零基础多图详解图神经网络(GNN/GCN)【论文精读】_哔哩哔哩_bilibili 0. 标题解读 0.1 主标题 A Gentle Introduction to Graph Neural Networks 直接说明本文是关于 图神经网络(GNN) 的简单的介绍 0.2 副标题 Neural networks have been adapted to leverage the structure and properties of graphs. We explore the components needed for building a graph neural network - and motivate the design choices behind them. 讲的是 : 图神经网络 被用在处理图的结构和特效上, 这篇文章来探索构建图神经网络需要哪些模块, 以及这背后的思想是什么 ...

2026年4月6日 · 4 分钟 · W1shBottle

CS336 Tokenization

说明:这是我在学习Stanford CS336(2025版)课程时整理的 Tokenization 笔记,主要依据课程讲义与课堂内容,并加入了我自己的理解与例子。内容涵盖 tokenizer 的基本概念、vocabulary size、character/byte/word 三种朴素分词方案的优缺点,以及 BPE(Byte Pair Encoding)的核心思路与动机。 tokenization(分词) 把原始文本(Unicode 字符串)切分并编码成 tokens / token IDs 的过程。 Tokenization = 将 Unicode 字符串通过 tokenizer encode 成 token 序列(通常是整数 ID) 并且支持 decode 把 ID 序列还原为字符串。 Tokenizer 提供: - encode: string -> token IDs (整数, 比如 15496, 11, 995, 0) - decode: token IDs -> string (字符串) Vocabulary size(词表大小) 就是Tokenizer 允许使用的“token 种类”的总数,也等价于 token ID 的取值范围大小。 更具体的说: Tokenizer 会维护一张“词表”(vocabulary): token(文本片段) ↔ token ID(整数编号) 的映射表。 Vocabulary size就是这张表里一共有多少个条目(多少个不同 token)。 因为每个 token 都对应一个唯一的整数 ID,所以也可以理解为: 一共有多少个可用的 token ID(通常 ID 从 0 到 vocab_size-1)。 举个极简例子 假设词表里只有 5 个 token: ...

2026年4月5日 · 3 分钟 · W1shBottle

操作系统笔记:内存 (下)

说明:本文为个人学习笔记,内容参考王道《操作系统》网课与配套讲义,按个人理解整理总结,仅用于学习交流,如有疏漏欢迎指正。 内存空间的扩充 覆盖 为了解决程序大小超过物理内存总和的问题, 引入了覆盖技术 思想 将程序分为多个段(多个模块) 常用的段常驻内存, 不常用的段在需要时调入内存 内存中分为一个"固定区", 和若干个"覆盖区" 区域类型 存放内容 调度规则 固定区 程序中需要常驻的核心段 调入后永久驻留,仅在程序运行结束时才调出 覆盖区 不常用、非核心的功能段 按需动态调度:用时调入,不用时调出,可被其他段覆盖 例子 注: 在计算机里,“透明”= 用户完全不用管,系统自动帮你做好。反过来,“不透明”= 用户必须手动操心、手动配置,系统不会自动帮你做。 为什么这叫 “不透明”? 现代虚拟内存(分页 / 分段):程序员完全不用管内存,写代码时默认 “内存无限大”,系统自动帮你换入换出,这就是透明。 覆盖技术:程序员必须深度参与内存管理,从拆分段、设计覆盖区、声明结构,到保证调用逻辑,全要手动搞定,系统只负责执行你写的规则,不会帮你做任何决策。 交换 思想 内存空间紧张时,系统将内存中某些进程暂时换出外存,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度) 在进程因为内存紧张被调出的时候, 进程的PCB需要留在内存(进入挂起队列), 即常驻内存, 这是因为在PCB中可以记录进程被调出到外存的具体位置 暂时换出外存等待的进程状态为挂起状态 问题 1) 应该在外存的什么位置保存被换出的进程? 在支持对换功能的操作系统中,磁盘空间会被划分为文件区和对换区两个独立部分,二者的管理逻辑完全围绕各自的核心目标设计。 文件区主要用于存放各类持久化的用户文件与程序数据,核心追求是存储空间的利用率,因此采用离散分配的方式来减少空间浪费、提升存储效率 而对换区仅占用磁盘的一小部分空间,专门用于临时存放被换出内存的进程数据,由于对换的 I/O 速度直接影响系统的整体运行效率,所以对换区的管理以换入换出速度为核心目标,通常采用连续分配的方式来减少磁盘寻道时间、提升读写效率,最终实现对换区的 I/O 速度远快于文件区,保障进程调度的高效性。 2) 什么时候应该交换 交换通常发生在许多进程运行且内存吃紧时进行, 而系统负荷降低就暂停 3) 应该换出哪些进程 可优先换出阻塞进程 换出优先级低的进程 为了防止优先级低的进程在被调入内存后很快又被换出, 有的系统还会考虑进程在内存的驻留时间(PCB常驻内存, 并不会被换出外存) 虚拟存储技术 传统存储管理方式的特征和缺点 一次性: 作业必须一次性全部装入内存后才能开始运行, 这会造成两个问题 : 作业很大时, 不能全部装入内存, 导致大作业无法运行 当大量作业要求运行时, 由于内存无法容纳所有作业, 因此只有少量作业能运行, 导致多道程序并发度下降 驻留性: 一旦有作业被装入内存, 就会一直驻留在内存中, 直至作业运行结束. 事实上, 在一个时间段内, 只需要访问作业的一小部分数据即可正常运行, 这就会到时了内存中驻留大量的, 暂时用不到的数据, 造成内存资源浪费 虚拟内存的定义和特征 定义 程序装入时,仅将很快会用到的部分装入内存,暂时用不到的部分留在外存,程序即可开始执行。 程序执行中,若访问的信息不在内存,由操作系统将所需信息从外存调入内存,再继续执行。 若内存空间不足,由操作系统将内存中暂时用不到的信息换出到外存。 在操作系统管理下,用户看来有一个比实际内存大得多的内存,这就是虚拟内存。 特征 多次性:无需在作业运行时一次性全部装入内存,允许被分成多次调入内存。 对换性:在作业运行时无需一直常驻内存,允许在作业运行过程中,将作业换入、换出。 虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量远大于实际的容量。 如何实现虚拟内存技术 虚拟内存技术,允许一个作业分多次调入内存。如果采用连续分配方式,会不方便实现。因此,虚拟内存的实现需要建立在离散分配的内存管理方式基础上。 ...

2026年4月5日 · 3 分钟 · W1shBottle

操作系统笔记:内存 (中)

说明:本文为个人学习笔记,内容参考王道《操作系统》网课与配套讲义,按个人理解整理总结,仅用于学习交流,如有疏漏欢迎指正。 摘要 本文整理操作系统内存管理中三类经典机制与考点: 基本分页存储管理:页表、地址变换、TLB、两级页表 基本分段存储管理:段表、越界检查、分段与分页对比 段页式管理方式:分段 + 分页结合后的地址转换 一、基本分页存储管理 1. 概念 将内存空间分为一个个大小相等的分区,每个分区称为一个 “页框”(页框 = 页帧 = 内存块 = 物理块 = 物理页面)。 将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为 “页”/“页面”。 每个页面有一个编号,称为 页号(从 0 开始) 操作系统以页框为单位为进程分配内存 进程的各页面与内存页框存在映射关系 各页面不必连续存放,可装入不相邻页框中(离散分配) 为了知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表(通常存放在 PCB 中): 一个进程对应一个页表 进程的每个页面对应一个页表项 每个页表项由 “页号” 和 “块号” 组成(逻辑概念) 页表记录页号与内存块号(页框号)的映射关系 每个页表项的长度是一样的 1.1 每个页表项占多少字节? 页表项逻辑上分为页号和块号,但通常只有 块号(以及控制位) 真正占存储空间;页号可以隐含(类比数组下标)。 注意:页表记录的是 内存块号,而不是内存块的起始地址。 j 号内存块的起始地址 = j × 内存块大小 2. 地址转换 2.1 连续存储(对比理解) 当进程在内存中连续存储时,重定位寄存器记录进程在内存中的起始位置,则: 物理地址 = 逻辑地址 + 起始位置 2.2 分页存储下的地址转换 当使用分页存储时,若要访问逻辑地址 A: 确定逻辑地址 A 对应的 页号 P 查页表找到 P 号页面在内存中的起始位置(通过页框号计算) 确定逻辑地址 A 的 页内偏移量 W 因此: ...

2026年4月3日 · 2 分钟 · W1shBottle

操作系统笔记:内存 (上)

说明:本文为个人学习笔记,内容参考王道《操作系统》网课与配套讲义,按个人理解整理总结,仅用于学习交流,如有疏漏欢迎指正。 摘要 本文梳理操作系统内存管理中的几个核心概念:内存的作用、地址转换(装入与重定位)、链接方式、内存保护与连续分配策略,并对常见动态分区分配算法进行对比,理解碎片与紧凑的必要性。 内存的作用 程序在执行前需要先装入内存,CPU 才能对其进行处理。内存的核心作用之一是缓和 CPU 与硬盘之间的速度矛盾: 硬盘/外存先把即将使用的数据读取到内存; CPU 需要数据时直接访问内存,而不必反复访问硬盘; 从而显著提升整体执行效率。 地址转换(装入与重定位) 1)绝对装入(Absolute Loading) 特点: 程序装入内存之前就确定装入位置,在编译阶段就把逻辑地址直接转换为最终物理地址。 前提: 必须提前知道装入模块从哪个物理地址开始装入。 缺点: 灵活性极差:装入位置变化会导致地址全部失效。 2)静态重定位(Static Relocation) 特点:重定位过程在装入时完成。 例:若装入起始物理地址为 100,则所有与地址相关的值统一加上 100。 限制: 作业装入内存时一次性分配其所需全部空间; 运行期间不可移动(无法在内存中动态搬迁)。 3)动态重定位(Dynamic Relocation,现代 OS 常用) 特点: 编译/链接阶段仍使用逻辑地址; 装入内存后不立即把逻辑地址改写成物理地址; 运行时由硬件机制完成转换。 关键硬件支持: 重定位寄存器(Relocation Register):存放装入模块的起始物理地址(基址)。 地址转换: CPU 执行时:物理地址 = 逻辑地址 + 重定位寄存器(基址) 优势: 允许程序在内存中发生移动(更灵活,也更利于多道程序和内存紧凑)。 从写程序到程序运行(以 C 语言为例) 编写源代码:生成 *.c 编译:生成目标模块 *.o 链接:把多个目标模块 + 库函数链接成装入模块(可执行文件)*.exe 装入:把装入模块装入内存,此时确定其对应的实际物理地址范围 链接方式 1)静态链接 在运行前,把各目标模块及其所需库函数连接成一个完整可执行文件,之后不再拆分。 2)装入时动态链接 边装入边链接:装入模块进内存时再完成链接。 3)运行时动态链接 程序执行过程中,需要某个目标模块时才链接。 优点: 便于修改、更新; 便于实现对目标模块的共享(多个进程可共享同一模块)。 内存保护 1)设置上下限寄存器(Limit Registers) 上下限寄存器存放进程的地址范围(通常是物理地址上下界)。 进程访问某地址时,CPU 检查是否越界,越界则触发异常。 2)重定位寄存器 + 界地址寄存器 重定位寄存器(基址):起始物理地址 界地址寄存器(界限/长度):进程最大逻辑地址(或逻辑地址范围大小) 检查逻辑地址是否小于 界地址,通过后再做 逻辑地址 + 基址 得到物理地址。 ...

2026年3月30日 · 1 分钟 · W1shBottle

操作系统笔记:进程

说明:本文为个人学习笔记,内容参考王道《操作系统》网课与配套讲义,按个人理解整理总结,仅用于学习交流,如有疏漏欢迎指正。 摘要 本文梳理操作系统中进程的核心知识:进程的概念与特征、PCB 与组成结构、三态/五态模型、进程控制原语(创建、终止、阻塞与唤醒)以及进程通信方式(共享存储、消息传递、管道)。 1. 进程的概念和特征 1.1 概念(常见表述) 进程的典型定义: 进程是一个正在执行程序的实例。 进程是程序及其数据从磁盘加载到内存后,在 CPU 上执行的过程。 进程是一个具有独立功能的程序在一个数据集合上运行的过程。 1.2 特征(四个基本特征) 动态性:有产生、运行、消亡的过程。 并发性:多个进程在一段时间内并发推进。 独立性:进程是资源分配与调度的基本单位。 异步性:推进速度不可预知,需要同步机制保证正确性。 2. 进程的组成 进程由三部分组成,其中最核心是 PCB(进程控制块): PCB(Process Control Block) 程序段 数据段 记忆点:PCB 是进程存在与管理的关键依据。 3. 进程的状态与转换 五种状态(前三种为基本状态): 运行态(Running):占用 CPU,正在执行。 就绪态(Ready):具备运行条件,仅缺 CPU,等待调度。 阻塞态(Blocked/Waiting):等待事件/资源(除 CPU 外),暂停推进。 创建态(New):正在创建,尚未进入就绪队列。 终止态(Terminated):正在结束并从系统消失。 就绪态 vs 阻塞态 就绪态:只缺 CPU。 阻塞态:缺 事件/资源(I/O、信号、锁、数据等)。 3.1 三态模型 3.2 五态模型 4. 进程控制(原语) 操作系统中,进程控制常通过原语实现。 原语特点: 执行期间不可中断(原子性) 通常在内核态完成 保证进程控制操作一致、正确 4.1 进程的创建(Create) 父子进程关系: 创建者为父进程,被创建者为子进程 子进程可继承父进程部分资源;结束时资源归还父进程/系统 创建原语典型步骤: 分配 PID,申请空白 PCB(PCB 有限,失败则创建失败)。 分配资源(内存、文件、I/O 设备、CPU 时间等)。 初始化 PCB(标志信息、CPU 状态等),设置优先级等调度信息。 插入就绪队列,等待调度运行。 4.2 进程的终止(Exit / Terminate) 终止原因: ...

2026年3月24日 · 1 分钟 · W1shBottle

用 Streamlit + DeepSeek 做一个 AI 智能伴侣:从能跑到工程化的复盘

声明 / 致谢:此项目的最初版本是我在学习黑马程序员的网课时,跟着课程一步步敲出来的练习项目。课程链接:https://www.bilibili.com/video/BV1sHU9BmEne/?vd_source=b7fe282ae22dcad10ba845b5eea36a47。 本文更多是在此基础上做的个人复盘与工程化整理(如 .env、LICENSE、Topics、GitHub Actions、Ruff、README 徽章等),并记录我在同步、配置与 CI 上踩过的坑和解决方式。 这篇文章复盘我做 streamlit-ai-companion 的过程:前半部分是项目实现(Streamlit + DeepSeek API),后半部分是把仓库“工程化”的学习经历(.env、License、Topics、GitHub Actions、Ruff、README 徽章)。整体不是教程流水账,而是按“我遇到的问题 → 为什么 → 怎么解决”的方式写。 1. 项目简介:我做了什么 我做了一个基于 Streamlit 的 AI 智能伴侣聊天应用: 聊天 UI:st.chat_input + st.chat_message 可配置“伴侣信息”:昵称 + 性格(sidebar 动态修改) 流式输出:模型一边生成一边显示,聊天更自然 会话历史:保存为本地 JSON 文件,支持加载/删除 2. 为什么要做工程化(而不是只停留在能跑) 一开始我的项目确实能运行,但“能跑”和“可维护/可分享”是两回事: 需要别人一眼看懂怎么运行(README) 不能把 API Key 提交上去(.env 处理) 需要许可证声明(LICENSE) 最好能有自动检查(CI),避免以后改坏了都不知道 所以我给仓库补齐了这些“标配”。 3. 项目核心实现复盘(结合 AI_companion.py) 3.1 关键配置:模型、Base URL、环境变量 我把关键参数集中在文件顶部: DEEPSEEK_API_KEY:用环境变量读取 Key BASE_URL = "https://api.deepseek.com" MODEL_NAME = "deepseek-chat" SESSIONS_DIR = "sessions" 这样做的好处是:以后换模型/换环境变量名时不会到处改。 ...

2026年3月5日 · 2 分钟 · W1shBottle

Hello

你好,我是许愿瓶。

2026年2月23日 · 1 分钟 · W1shBottle