Introduction

My MainPage

欢迎来到刘益枫的博客!这是我的一个小空间* ⸜( •ᴗ• )⸝ *

主页:My MainPage

常用网站索引->快速通道

欢迎关注我的最新调教作品 《动离忧》

项目网页:T-RexCapricorn医疗多组学CodeGeeX军棋初音爬虫日本麻将美赛O奖头像魔术师

Welcome to Lewis Yik-Fung Lau’s Blog! This is a small space of mine.

My MainPage

List of frequently used websites->Website List

You are welcomed to pay attention to my latest Vocaloid-based song Arouse Worries about Department.

Project Webpages: T-Rex, Capricorn, Medical Multiomics, CodeGeeX, Kriegspiel, Mikucrawler, Japan Mahjong, ICM Outstanding Award, Heady Liar.

AI-2

干货|卷出顶级AI实验室(2)

进阶

(本人已授权小红书转载)

一、对AI的认知:

深度学习是个很强大的工具,万能近似定理(universal approximation theorem)[Hornik, 1991]理论证明具有隐含层(最少一层)感知机神经网络在激励函数(也称激活函数)为非常数函数的情况下具有逼近任何函数的作用。

  • 然而理论只是证明了其可能性,通常难以得到这种理想的状态,因此对于一般的深度学习模型来说,通常会设计比较复杂的结构,一方面增大其表达能力,从而得到更好的性能;另一方面增大其对参数的容错能力,使其更容易达到较好的性能。

  • 从万能近似定理也可以看出来,神经网络一般都由线性结构和激励函数(非线性结构)组成,最简单的神经网络结构就是由激励函数分开的全连接层(多层感知机,MLP)。

  • 然而,全连接层参数众多,需要的资源太多、计算速度太慢,因此,将全连接层替换为卷积层,将激励函数变为池化层(maxpool或者avgpool),就变成了最基本的卷积神经网络(CNN),著名的LeNet和AlexNet就是CNN,只不过它们用的是多channel的卷积核。

  • 以上的网络都是从前往后依次序的结构,在反向传播的时候容易产生遗忘(梯度消失)的现象,越靠近输入的参数梯度的信号越弱,导致模型容易忽视底层所提取到的特征,例如边缘、纹理等等。因此,ResNet加上一个shortcut连接,即x’=x+F(x),这样,梯度就能以更快的速度传回前面的模块,从而使得模型能够更好地注意底层特征。而DenseNet进一步推广,在每两个模块之间都加上shortcut连接。

从以上的例子可以看出来,深度学习的研究的一种思路就是看到某个问题需要解决,就设计出一个巧妙的结构去解决它。例如,看到RNN容易导致遗忘问题,就让输入的序列两两之间交互,于是便有了attention。而如果是QA,则需要让输入和输出序列之间、输出序列各token之间都有交互,于是就有了Transformer。

然而,深度学习虽然是万能的工具,但通常需要极其大的数据量去训练(例如GPT4、Kimi Chat等目前较好的大语言模型需要上TB的tokens),而对于一些数据比较少的较简单的任务(比如我之前做的多组学探究只有数百个样本),深度学习往往难以奏效,这时需要考虑一些其它的机器学习算法,例如XGBoost、KNN、SVM等。通常这些算法能带来相当令人满意的精度,其中XGBoost结合SHAP[S. Lundberg&Su-In Lee, 2017]等工具还可以做出比较好的可解释性分析。

对于不同的领域,有不同的研究风格,例如NLP领域,目前LLM就是在Transformer结构上不断进行扩大、修改结构(如pre-norm和post-norm、positional embedding、修改激活函数),而传统NLP则将机器学习算法、数据库等技术融入到BERT等语言模型中,用来实现即插即用、个性化等功能。计算机视觉领域则是在基本CNN上不断推陈出新,如diffusion模型(大家可以想一下为什么diffusion模型用在文本生成任务上表现不尽人意)。另外,对于AI4Science这个方向,因为数据类型和数据量各异,则是要用到多种算法,甚至需要用到一些传统机器学习算法,例如像DNA序列、蛋白质序列等,可以用Transformer(例如Alphafold);对于像核磁共振等图形,可以用CNN、diffusion等模型;而像组学研究,特征离散且数量巨多,则可以用XGBoost算法。

二、常用工具Pytorch介绍

作为AI相关的研究者,最痛苦的莫过于安装环境。一般会去官网下载安装Anaconda或者Miniconda,而对于AI研究者来说,最重要的包莫过于PyTorch了。

  • 所有与PyTorch相关的问题都最好先在https://pytorch.org/上面查询一遍,尤其是查询PyTorch文档(上边栏的Docs下拉菜单里面的PyTorch,直接点搜索符号出来的是Blog)
  • 现在PyTorch的版本已经更新到2.1.x了,理论上兼容1.x的版本,但是会有一些接口上的不同。
  • 安装PyTorch
    • 可以到官网https://pytorch.org/get-started/locally/查找对应的安装命令,请注意,官网安装命令默认安装最新版本的PyTorch,实际情况因为算力太高、CUDA版本太低或者python版本较老,可能需要寻找较老版本的PyTorch
    • 安装PyTorch需要先考虑显卡的算力,有些高端显卡(例如GeRorce RTX3090、4090),算力太高,低版本的PyTorch不支持。一些极端情况,高端显卡配上低版本的CUDA,没有合适的PyTorch版本,因此,这种情况需要更新CUDA(总不可能换块显卡吧QAQ)。CUDA版本可以通过nvidia-smi命令查看右上角CUDA处或者nvcc -V查询(但需要注意的是,这两者查到的版本可能是不同的。通常后者版本不大于前者的版本就行)
    • 根据对应的CUDA版本,查询对应的PyTorch适合的版本(https://pytorch.org/get-started/previous-versions/上cudatoolkit的可选范围)
    • 有时国内的一些服务器不能访问torch官网,因此安装pytorch可能需要考虑更换源,例如
    • 有些时候因为网络不畅而导致下载很慢,可以手动在https://download.pytorch.org/whl/cu1xx/torch_stable.html(例如https://download.pytorch.org/whl/cu110/torch_stable.html)上面寻找到合适的安装包
    • 用torch.cuda.is_available() (记得先import torch)命令查看你的pytorch版本是不是装正确了(你显卡能不能用)
  • PyTorch的一些重要包
    • torch.nn.Module和torch.nn.functional
      • 前者是一个类,除了要进行对应的计算,还要对模块中的参数等进行管理,而后者只是单纯的计算,需要手动提供对应的参数。
      • 例如nn.Linear包含了一个全连接层,内含了全连接层的weight和bias(如果设定bias=True)参数,而nn.functional.linear需要手动提供weight和bias(默认None)
      • nn.Module其实是一大堆常见模块,例如n维卷积层、池化层(最大池化Maxpool、平均池化Avgpool等)、非线性层、归一化层(组归一化、批归一化、例归一化)、整合结构(GRU、RNN、LSTM、Transformer(含Encoder、Decoder和单独的layer))、全连接层、dropout、损失函数等等,其中除整合结构外,绝大部分都有对应的nn.functional函数。
      • 一般各种神经网络用到的就是nn.Module下面的各种模块(为了适配nn.sequential()),而nn.functional一般会用于loss的计算以及模块间和最终输出前单独的非线性函数。
      • 这两个再配合torch.view/reshape等函数,就能搭建一个比较复杂的神经网络了
    • torch.optim
      • 这里面包含了一些常见的optimizer,如SGD、Adam、AdamW、RMSprop;以及常用的学习率调节函数(torch.optim.lr_scheduler),如LinearLR,OneCycleLR等等
    • torch.distributed
      • 对于大型项目(如LLM),可能会涉及到多张显卡,因此显卡之间的通讯就非常重要,这里面包含了许多分布式操作函数,例如DDP
    • torch的梯度机制
      • 一般的流程:
        • for epoch in range(num_epoch):
        • model.train(); for x, target in train_dataset: model.zero_grad(); y = model(x); loss = loss_function(y, target), loss.backward(); optimizer.step(); scheduler.step()
        • model.eval(); total_loss = 0; for x, target in eval_dataset: model.zero_grad(); y = model(x); total_loss += loss_function(y, target); total_loss = total_loss / len(eval_dataset)
        • if total_loss < min_loss: torch.save(model)
      • model.train()和model.eval():启停模型其中的batch norm和dropout
      • loss.backward():传入反向传播命令
      • optimizer.step():有时需要手动调用optimizer和scheduler去调整训练梯度的参数和学习率
      • with torch.no_grad()
        • pytorch有自动求导机制,梯度计算是累加式的,每推算一次就会累加一次梯度相关的参数,因此在evaluation推理期间,需要用这个语句停止自动求导
        • 取消自动求导可以降低存储需要,提高计算速度
    • torch.nn.init
      • 在神经网络初始化时,通常是随机的参数,而用Xavier、Kaiming等初始化策略,可以使得神经网络在初始时就能让反向传播各层方差几乎相等,从而降低梯度收缩和梯度爆炸的可能性。
    • torch.utils.data.Dataset
      • 组织训练、测试和验证数据最常用的类,可以定义批大小、是否随机打乱等等,还支持继承该类进行自定义
  • PyTorch一些容易被忽略的功能
    • torchsummary
      • 可以直接打印函数每一层输出的size,还可以统计每一层的参数数量和总参数量方便写函数的时候debug
      • 用pip install torchsummary
        • from torchsummary import summary
        • summary(your_model, input_size=(bsz, channels, H, W)),其中input size根据设计模型的输入变化,不一定是4维
    • torch.einsum
      • 对于形象能力强但抽象能力弱的同学,能够形象描述对应的操作,但很难写对应代码的uu,可以试着用torch.einsum
      • 这是基于爱因斯坦求和约定:如果两个相同的指标出现在指标符号公式的同一项中,则表示对该指标遍历整个取值范围求和。
      • 一般形式:torch.einsum(用符号描述你需求的字符串,输入的list),字符串的格式为:“矩阵1的shape、矩阵2的shape…->输出矩阵的shape”。
      • 例如:
        • torch.einsum(‘ij, jk->ik’, [a, b])就是求a与b的矩阵乘法;
        • torch.einsum(‘jj’, a)就是求矩阵的迹;
        • torch.einsum(‘…ij-> …ji’, A)就是把A(不管有几维)的最后两维进行转置;
        • torch.einsum(‘ij->’, a)就是矩阵求和
        • torch.einsum(‘ij->j’, a)就是按列求和
      • einsum在某些时候(例如二维矩阵点积)可能比对应的函数慢,但有时(例如高维矩阵点乘求和)却可能比相应的函数快

AI-1

干货|卷出顶级AI实验室(1)

(本人已授权小红书转载)

目前NLP这个方向的研究日新月异,想要能够从学术小白到发出自己的第一篇论文,除了掌握基础的工具之外,还得跟踪最新的科研方向,多与身边的peer进行交流,找到尚未发现的研究点。

基础工具

数学:其实NLP方向对数学的要求并不算特别高,掌握常用的线性代数和贝叶斯公式就行,最多加一点复杂度的知识,大多数NLP方向的开发都是非常tricky的,像ResNet、DenseNet也就仅仅是网络架构层次的上的变换,更多的只是收集数据集、或者把某一层的位置前后挪一挪就是一个新的work(例如Transformer里面的pre-norm或者post-norm)。一般用到数学的地方就是各种公式推导(线性代数)以及如何计算metric(例如PPL、pass@k、MSE、BERT-score等等)

需要高深数学工具的都并非本领域的研究重点(例如各种optimizer或者diffusion),当然如果有志于开发更general的工具可以适当多储备一些随机过程和微积分的知识即可。

编程语言:如果只是改网络架构,那么只需要python就行,刷leetcode用到的基础语法可能在更加深入的研究中显得捉襟见肘,可以多了解一些python的进阶语法,例如python装饰器。

对于package而言,numpy、pytorch(很老的项目可能会用tensorflow,直接忽略掉这些项目也没问题)、csv、pandas、matplotlib、tqdm、json(jsonlines)、os、transformers等等是必须要掌握的工具,而pytorch是重中之重,要学会看https://pytorch.org/上面的文档。而且,python最重要的是看懂其他人的package,例如基于ChatGPT的研究通常需要熟悉openai库。

如果想要进一步去深入研究,可能会遇到各种各样其他的语言,例如C++、Rust甚至Java,唯一的要求是学会类比,看懂程序是怎么做的,然后能够翻译成python。

如果是学生的话,可以免费使用Copilot,一般给一些自然语言提示,copilot能够自动补全剩下的代码,可以成倍提高效率。

计算机知识:即便是最壕的组,顶配8台A100,在训练大模型的时候,也得考虑显存管理的问题。至少要对MB、GB,以及float32、float64、int等基本单位和类型有一个清晰的认识。例如假设一个float32模型参数量为n,那么nx4(float32一个数为4B)x6(用Adam optimizer训练的时候正向、反向共需要存储6个相应的数),大概就是单卡训练所需要的显存。

需要知道git和bash相关的操作(例如如何git clone别人的工作,如何移动文件夹),在实际经验中还得用一些其他的工具,例如scp、zip、tar、tmux(防止成为学堂路车神),以及nvidia-smi(查看显卡状态)、top(查看进程和cpu状态)、如何配置跳板机等等;还有一些其他边角知识,例如对于一个乱码的数据集,你得需要知道能够在ascii、UTF-8、GB2312等编码之间切换。

这些知识几乎没有哪个中国大学的CS专业课上面会讲,大多都是学生一步步摸索出来(看stack overflow/github论坛/CSDN/知乎 etc)或者对应习题课的助教1to1讲解来的。光学课程、刷leetcode也是没用的,还得有实操经验(这是转码与计算机科班生的最大差距)。

AI知识:非CS专业学生学吴恩达《深度学习》作为进阶确实也够了,要是想要挑战更难的课程,可以找找美国名校(MIT、CMU、Berkeley、Stanford等)的课程,清华的很多课也是借鉴了一部分这些课程的内容和习题的。也可以用《Deep Learning》(理论,有中文版)和《Dive into Deep Learning》(实践、有中文版、有在线Google colab免费试炼场),甚至可以跟着Pytorch官方教程试着开发CNN、NLP等等项目,都是开源的。

找到大方向(NLP、CV、Robotics、Graphics等等):

可以了解对应方向的一些代表作,找到自己的兴趣所在(NLP:Transformer、Word2vec;CV:CNN、ViT、Diffusion、ResNet;Robotics:PaLM;Graphics:NeRF),我当时入坑NLP就是因为看了Transformer以及相关的一些应用。然后根据Google Scholar上的引用和被引用再拓展自己的视野。

找到具体研究的点

多了解了解最新的研究方向,可以与同学和导师沟通,最好是加入一个实验室,看有什么迫切需要解决的问题,或者长期以来没有用AI解决的任务,又或者紧跟时事,趁着别人还没发出论文,先把别人的工作发表了。

然后根据所了解到的论文,去Google Scholar上搜索对应论文的引用该文章的其他论文,确认该任务没有AI解决的先例,或者AI的效果不好。一般一个灵光一闪的点,95%的概率别人已经用CNN或者BERT等比较简单的结构先占了个坑。一般一个工作的目标是在一个或者多个metric上超过SoTA(state-of-the-art,目前最好结果)。当然,还有其他的工作,比如创立数据集(基准,benchmark),然后测试其他模型在该数据集上的结果。

对于先前只有CNN或者Word2vec等基础模型的工作,可以用更好的模型(ViT/Diffusion、Transformer)进行替换。对于已经有更好模型的工作,可以考虑修改网络结构(比如更改position embedding的方式,更改ReLU为Swish等等),不过不是随便乱改,要有一定的理由,这些理由可以从先前论文的conclusion和limitation部分,或者跑出来的结果进行分析(如BERT因为Attention要让所有的token直接都有联系,需要O(n^2)的空间复杂度,可以通过减少attention的感受域变成O(nk),k远小于n)