写在前面
【三年面试五年模拟】旨在整理&挖掘AI算法工程师在实习/校招/社招时所需的干货知识点与面试方法,力求让读者在获得心仪offer的同时,增强技术基本面。也欢迎大家提出宝贵的优化建议,一起交流学习💪
欢迎大家关注Rocky的公众号:WeThinkIn
欢迎大家关注Rocky的知乎:Rocky Ding
AIGC算法工程师面试面经秘籍分享:WeThinkIn/Interview-for-Algorithm-Engineer欢迎大家Star~
获取更多AI行业的前沿资讯与干货资源
WeThinkIn最新福利放送:大家只需关注WeThinkIn公众号,后台回复“简历资源”,即可获取包含Rocky独家简历模版在内的60套精选的简历模板资源,希望能给大家在AIGC时代带来帮助。
大家好,我是Rocky。
又到了定期阅读《三年面试五年模拟》文章的时候了!本周期共更新了80多个AIGC面试高频问答,依旧干货满满!诚意满满!
《三年面试五年模拟》系列文章帮助很多读者获得了心仪的算法岗offer,收到了大家的很多好评,Rocky觉得很开心也很有意义。
在AIGC时代到来后,Rocky对《三年面试五年模拟》整体战略方向进行了重大的优化重构,在秉持着Rocky创办《三年面试五年模拟》项目初心的同时,增加了AIGC时代核心的版块栏目,详细的版本更新内容如下所示:
- 整体架构:分为AIGC知识板块和AI通用知识板块。
- AIGC知识板块:分为AI绘画、AI视频、大模型、AI多模态、数字人这五大AIGC核心方向。
- AI通用知识板块:包含AIGC、传统深度学习、自动驾驶等所有AI核心方向共通的知识点。
Rocky已经将《三年面试五年模拟》项目的完整版构建在Github上:https://github.com/WeThinkIn/Interview-for-Algorithm-Engineer/tree/main,本周期更新的80+AIGC面试高频问答已经全部同步到项目中了,欢迎大家star!
本文是《三年面试五年模拟》项目的第十七式,考虑到易读性与文章篇幅,Rocky本次只从Github完整版项目中摘选了2024年6月24号-2024年7月7号更新的部分经典&干货面试知识点和面试问题,并配以相应的参考答案(精简版),供大家学习探讨。
在《三年面试五年模拟》版本更新白皮书,迎接AIGC时代中我们阐述了《三年面试五年模拟》项目在AIGC时代的愿景与规划,也包含了项目共建计划,感兴趣的朋友可以一起参与本项目的共建!
当然的,本项目中的内容难免有疏漏与错误之处,欢迎大家在文末评论进行补充优化,Rocky将及时更新完善到Github上!
希望《三年面试五年模拟》能陪伴大家度过整个AI行业的职业生涯,并且让大家能够持续获益。
So,enjoy:
正文开始
目录先行
AI绘画基础:
-
Stable-Diffusion-3有哪些改进点?
-
Playground-V2模型有哪些特点?
AI视频基础:
-
Sora有哪些创新点?
-
SVD(Stable-Video-Diffusion)有哪些创新点?
深度学习基础:
-
Transformer的输入包含哪些内容?
-
介绍一下Transformer中的Self-Attention机制
机器学习基础:
-
什么是哈达玛积,在AI领域有哪些典型应用?
-
什么是NeRF(Neural-Radiance-Fields)技术?
Python编程基础:
-
什么是python的字符串格式化技术?
-
Python中有哪些常用的设计模式?
模型部署基础:
-
如何将AI模型缓存到内存中,这么做有什么好处?
-
什么是AI领域的延迟和吞吐量?
计算机基础:
-
Linux中的tail命令使用大全
-
Linux中有哪些常用的查看文件夹占用空间的命令?
开放性问题:
-
AI行业现阶段以及未来能够落地商用的领域有哪些?
-
如何给一个完全没有接触过AIGC的人介绍AIGC?
AI绘画基础
【一】Stable-Diffusion-3有哪些改进点?
Rocky认为Stable Diffusion 3的价值和传统深度学习时代的“YOLOv4”一样,在AIGC时代的工业界、应用界、竞赛界以及学术界,都有非常大的学习借鉴价值,以下是SD 3相比之前系列的改进点汇总:
- **使用多模态DiT作为扩散模型核心:**多模态DiT(MM-DiT)将图像的Latent tokens和文本的tokens拼接在一起,并采用两套独立的权重处理,但是在进行Attention机制时统一处理。
- **改进VAE:**通过增加VAE通道数来提升图像的重建质量。
- **3个文本编码器:**SD 3中使用了三个文本编码器,分别是CLIP ViT-L(参数量约124M)、OpenCLIP ViT-bigG(参数量约695M)和T5-XXL encoder(参数量约4.7B)。
- **采用优化的Rectified Flow:**采用Rectified Flow来作为SD 3的采样方法,并在此基础上通过对中间时间步加权能进一步提升效果。
- **采用QK-Normalization:**当模型变大,而且在高分辨率图像上训练时,attention层的attention-logit(Q和K的矩阵乘)会变得不稳定,导致训练出现NAN,为了提升混合精度训练的稳定性,MM-DiT的self-attention层采用了QK-Normalization。
- **多尺寸位置编码:**SD 3会先在256x256尺寸下预训练,再以1024x1024为中心的多尺度上进行微调,这就需要MM-DiT的位置编码需要支持多尺度。
- **timestep schedule进行shift:**对高分辨率的图像,如果采用和低分辨率图像的一样的noise schedule,会出现对图像的破坏不够的情况,所以SD 3中对noise schedule进行了偏移。
- **强大的模型Scaling能力:**SD 3中因为核心使用了transformer架构,所以有很强的scaling能力,当模型变大后,性能稳步提升。
- **训练细节:**数据预处理(去除离群点数据、去除低质量数据、去除NSFW数据)、图像Caption精细化、预计算图像和文本特征、Classifier-Free Guidance技术、DPO(Direct Preference Optimization)技术
【二】Playground-V2模型有哪些特点?
Playground系列AI绘画大模型到目前已经发展到第三个版本,也就是Playground V2.5,其特点主要有:
- 与SDXL相同模型架构。
- 与SDXL相比,增强了色彩和对比度(EDM框架),改善了跨多种长宽比的生成(均衡分桶策略),以及改善了中心人物的细节(SFT策略)。
- 其中EDM框架能在扩散模型的扩散过程最终“时间步长”上表现出接近零的信噪比。这消除了对偏移噪声的需求,让Playground V2.5能够生成背景是纯黑色或纯白色的图像。
- 其中SFT策略主要使用一个高质量的小数据集对预训练的扩散模型进行微调训练。而这个数据集通过用户评级自动策划。
- 从头开始训练(trained from scratch)。
- 设计MJHQ-30K测试集用于评估AI绘画大模型,主要是在高质量数据集上计算FID来衡量美学质量。MJHQ-30K是从Midjourney上收集的30000个高质量数据集,共包含10个常见的类别,每个类别包含3000个样本。
AI视频基础
【一】Sora有哪些创新点?
OpenAI对Sora的定位不只是视频生成工具,而是希望在此基础上开发出能够让计算机理解真实世界的算法与技术——“作为世界模拟器的视频生成模型”。在这个宏大愿景下最具潜力的技术基底之一便是生成式模型 (generative model)。
下面是Sora的一些创新点:
- **海量的数据:**在Sora的技术报告中,关于数据量级是一句话都没有提。这就说明,Sora使用了海量的高质量视频数据用作训练,Rocky相信未来全互联网的视频数据都会被Sora用作训练,同时在视频数据领域的数据生成、数据增强将会有非常大的机会。
- **灵活编码:**在Sora中,借鉴了大语言模型的构建方式,使用video compression network(convolutional VAEs)将视频数据tokenizer化,获得visual patches,使得任何长度和内容的视频都能编码成AI视频模型可以直接处理(输入/输出)的embeddings。首先video compression network将输入视频的时间和空间两个维度同时进行压缩,编码成一个和视频大小成正比的3D visual patch矩阵,然后再将其展开成1D array of patches Embeddings,送入到后续的DiT model中。这样可以带来两个好处,分别是让Sora能够生成不同分辨率的视频分和生成的视频的边框更加合理。
- **DiT模型架构:**Sora使用了DiT(Diffusion Transformer)作为核心架构,这让Transformer在AI领域的大一统更进一步。
- **精细化数据标注:**和DALL-E 3一样,OpenAI用内部标注工具(可能是GPT4-4o等)给视频数据进行详尽的描述标注,从而提升Sora模型生成视频与输入prompt的一致性、生成视频的质量和视频中正确显示文本的能力。Rocky认为数据工程是非常关键的一点,无论是传统深度学习时代还是AIGC时代,都是AI领域的杀手锏。
- **让AI视频领域的Scaling Law成立:**保证模型越大,数据越多,效果就越好。Sora也不例外。一句话概括Sora的贡献,便是:在足量的数据,优质的标注,灵活的编码下,scaling law 在 transformer + diffusion model 的架构上继续成立。
【二】SVD(Stable-Video-Diffusion)有哪些创新点?
Rocky认为SVD(Stable Video Diffusion)模型非常有价值,其开源精神让我们动容,下面是SVD模型的主要创新点:
- 基于Stable Diffusion 2.1模型架构
- 海量数据集:StabilityAI使用了一个包含5.8亿个视频剪辑的巨大数据集,来训练SVD模型。为了筛选高质量数据,首先需要检测每个视频中的不同镜头和转场,并且评估每个镜头中的运动信息,然后为每个镜头自动生成描述文字和每个镜头的美学效果等。
- 数据精细化处理:(1)级联切换检测:采用级联的切换检测方法识别视频中的场景转场。(2)运动信息提取:基于稠密光流估计每个视频片段的运动信息。(3)文本描述生成:为每个视频片段自动生成三种形式的文字描述。(4)质量评估:使用CLIP等方法评估每个片段的视觉质量、文本匹配度等。(5)过滤去噪:根据上述评估指标过滤掉质量较差的视频片段。经过层层筛选,最后保留了一个约1.5亿视频片段的超高质量数据集,为后续的SVD模型训练奠定重要基础。
- 多阶段训练:SVD模型在模型训练方面也与传统方法不同,其采用了一个三层训练架构。第一阶段是进行图像预训练,初始化一个图像生成模型。第二阶段是在已经构建的大规模视频数据集上进行视频预训练,学习运动表征。第三阶段是在一个小规模的高质量视频数据集上进行微调。这种分阶段的训练策略可以让模型更好地生成高保真视频。
深度学习基础
【一】Transformer的输入包含哪些内容?
原生Transformer的输入包括词嵌入(word embeddings)和位置嵌入(positional encodings)两个部分,以下是对Transformer输入的详细讲解,特别是位置嵌入的含义。
Transformer 的输入
-
词嵌入(Word Embeddings):
- 每个单词通过嵌入层转换为一个高维向量。这些向量是从预训练模型(如Word2Vec、GloVe)或通过Transformer的嵌入层生成的。
- 词嵌入捕捉了单词的语义信息,使模型能够理解单词的含义和上下文。
-
位置嵌入(Positional Encodings):
- 因为Transformer架构中没有内置的顺序信息(如RNN中的时间步),所以需要显式地加入位置信息,以便模型能够感知输入序列中每个单词的位置。
- 位置嵌入是与词嵌入向量相加的,这样每个单词的向量不仅包含其语义信息,还包含其在序列中的位置。
位置嵌入(Positional Encodings)
位置嵌入是用于向模型提供位置信息的一种方法。Transformer的位置嵌入通常使用正弦和余弦函数来编码位置。具体方法如下:
数学公式
位置嵌入向量的每个维度是通过正弦和余弦函数计算的:
P
E
(
p
o
s
,
2
i
)
=
sin
(
p
o
s
1000
0
2
i
d
m
o
d
e
l
)
PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{\frac{2i}{d_{model}}}}\right)
PE(pos,2i)=sin(10000dmodel2ipos)
P
E
(
p
o
s
,
2
i
+
1
)
=
cos
(
p
o
s
1000
0
2
i
d
m
o
d
e
l
)
PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{\frac{2i}{d_{model}}}}\right)
PE(pos,2i+1)=cos(10000dmodel2ipos)
其中:
- p o s pos pos 表示单词在序列中的位置。
- i i i 表示位置嵌入向量的维度索引。
- d m o d e l d_{model} dmodel 是嵌入向量的维度。
含义和作用
-
位置区分:
- 位置嵌入使得每个位置的表示是唯一的,这样模型可以区分序列中的不同位置。
-
周期性:
- 正弦和余弦函数的周期性质帮助模型捕捉到不同尺度的相对位置关系。正弦函数在不同频率下的变化使得模型能够感知到序列中的局部和全局结构。
-
可微性和连续性:
- 使用正弦和余弦函数生成的位置嵌入是可微分的,这对模型训练有利。
示例代码
以下是如何在PyTorch中实现位置嵌入的示例:
import torch
import math
class PositionalEncoding(torch.nn.Module):
def __init__(self, d_model, max_len=5000):
super(PositionalEncoding, self).__init__()
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0).transpose(0, 1)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:x.size(0), :]
return x
# Example usage:
d_model = 512
pos_encoding = PositionalEncoding(d_model)
input_tensor = torch.zeros(10, 32, d_model) # (sequence_length, batch_size, d_model)
output = pos_encoding(input_tensor)
【二】介绍一下Transformer中的Self-Attention机制
Transformer中的Self-Attention机制是其核心组件之一,用于捕捉输入序列中不同元素之间的相互关系。以下是对Self-Attention机制的详细介绍:
Self-Attention机制概述
Self-Attention机制的主要目标是为输入序列中的每个元素生成一个表示,表示考虑了该元素与序列中其他所有元素的关系。Self-Attention机制使得模型能够在一个序列中长距离依赖信息,从AI领域任务的效果。
计算过程
Self-Attention的计算过程可以分为以下几个步骤:
-
输入向量变换:
- 对于每个输入向量
x
i
\mathbf{x}_i
xi,使用三个不同的权重矩阵
W
Q
\mathbf{W}^Q
WQ , $\mathbf{W}^K$ ,
W
V
\mathbf{W}^V
WV 将其分别映射到查询(Query),键(Key),和值(Value)向量:
q i = x i W Q , k i = x i W K , v i = x i W V \mathbf{q}_i = \mathbf{x}_i \mathbf{W}^Q, \quad \mathbf{k}_i = \mathbf{x}_i \mathbf{W}^K, \quad \mathbf{v}_i = \mathbf{x}_i \mathbf{W}^V qi=xiWQ,ki=xiWK,vi=xiWV
- 对于每个输入向量
x
i
\mathbf{x}_i
xi,使用三个不同的权重矩阵
W
Q
\mathbf{W}^Q
WQ , $\mathbf{W}^K$ ,
W
V
\mathbf{W}^V
WV 将其分别映射到查询(Query),键(Key),和值(Value)向量:
-
计算注意力权重:
-
计算查询向量与所有键向量的点积,然后除以一个缩放因子 d k \sqrt{d_k} dk( d k d_k dk是键向量的维度),最后通过Softmax函数得到注意力权重:
Attention ( Q , K , V ) = Softmax ( Q K T d k ) V \text{Attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \text{Softmax}\left(\frac{\mathbf{QK}^T}{\sqrt{d_k}}\right)\mathbf{V} Attention(Q,K,V)=Softmax(dkQKT)V -
对于每个查询向量 q i \mathbf{q}_i qi ,计算与所有键向量 k j \mathbf{k}_j kj 的注意力权重:
α i j = exp ( q i × k j / d k ) Z \alpha_{ij} = \frac{\exp(\mathbf{q}_i \times \mathbf{k}_j / \sqrt{d_k})}{Z} αij=Zexp(qi×kj/dk)
Z = ∑ j = 1 n exp ( q i × k j / d k ) Z = \sum_{j=1}^n \exp(\mathbf{q}_i \times\mathbf{k}_j / \sqrt{d_k}) Z=j=1∑nexp(qi×kj/dk)
-
-
计算注意力输出:
- 使用注意力权重对值向量进行加权求和,得到每个输入向量的新表示:
z i = ∑ j = 1 n α i j v j \mathbf{z}_i = \sum_{j=1}^{n} \alpha_{ij} \mathbf{v}_j zi=j=1∑nαijvj
- 使用注意力权重对值向量进行加权求和,得到每个输入向量的新表示:
多头注意力机制(Multi-Head Attention)
在实际应用中,Transformer模型通常使用多头注意力机制。多头注意力机制通过并行计算多个独立的Self-Attention,然后将结果拼接在一起并通过线性变换得到最终的输出:
-
多头计算:
- 将查询、键和值向量分别映射到不同的子空间中进行独立的Self-Attention计算:
head h = Attention ( Q h , K h , V h ) \text{head}_h = \text{Attention}(\mathbf{Q}_h, \mathbf{K}_h, \mathbf{V}_h) headh=Attention(Qh,Kh,Vh) - 其中 h h h 表示第 h h h 个头。
- 将查询、键和值向量分别映射到不同的子空间中进行独立的Self-Attention计算:
-
拼接和线性变换:
- 将所有头的输出拼接在一起,并通过一个线性变换得到最终的输出:
MultiHead ( Q , K , V ) = Concat ( head 1 , … , head h ) W O \text{MultiHead}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) \mathbf{W}^O MultiHead(Q,K,V)=Concat(head1,…,headh)WO
- 将所有头的输出拼接在一起,并通过一个线性变换得到最终的输出:
Self-Attention的优势
- 捕捉长距离依赖关系:Self-Attention机制能够直接建模输入序列中任意两个位置之间的依赖关系,适合处理长序列数据。
- 并行计算:与RNN不同,Self-Attention机制可以在计算时并行处理输入序列中的所有元素,提高了计算效率。
- 表示能力强:通过多头注意力机制,模型能够在不同子空间中捕捉到不同的依赖关系,提高了表示能力。
机器学习基础
【一】什么是哈达玛积,在AI领域有哪些典型应用?
哈达玛积(Hadamard Product)
哈达玛积(Hadamard Product),又称逐元素乘积(element-wise product),是线性代数中的一种矩阵运算。它与标准矩阵乘法不同,哈达玛积是对两个相同大小的矩阵的对应元素进行乘积运算。
哈达玛积通过逐元素乘积,它能够有效地进行特征组合、权重计算和信息传播,增强模型的表达能力和计算效率。
数学定义
给定两个相同大小的矩阵 $ A $ 和 $ B $,它们的哈达玛积 $ C $ 定义如下:
C = A ∘ B C = A \circ B C=A∘B
其中 $ C $ 的每个元素 $ c_{ij} $ 计算为:
c i j = a i j × b i j c_{ij} = a_{ij} \times b_{ij} cij=aij×bij
例如,假设有以下两个矩阵 $ A $ 和 $ B $:
A = [ 1 2 3 4 ] , B = [ 5 6 7 8 ] A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}, \quad B = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} A=[1324],B=[5768]
它们的哈达玛积 $ C $ 为:
C = A ∘ B = [ 1 × 5 2 × 6 3 × 7 4 × 8 ] = [ 5 12 21 32 ] C = A \circ B = \begin{bmatrix} 1 \times 5 & 2 \times 6 \\ 3 \times 7 & 4 \times 8 \end{bmatrix} = \begin{bmatrix} 5 & 12 \\ 21 & 32 \end{bmatrix} C=A∘B=[1×53×72×64×8]=[5211232]
哈达玛积在深度学习中的应用
在AI行业中,哈达玛积有多种重要的应用,特别是在AIGC、传统深度学习、自动驾驶领域中。下面是一些典型的应用和作用:
-
注意力机制:
在注意力机制(Attention Mechanism)中,哈达玛积被用来计算注意力权重。例如,在自注意力(Self-Attention)机制中,通过计算输入向量之间的相似度,利用哈达玛积对这些相似度进行加权,从而突出输入序列中重要的部分。 -
门控机制:
在循环神经网络(RNN)和长短期记忆网络(LSTM)中,哈达玛积用于门控机制。例如,LSTM中的输入门、遗忘门和输出门的计算都涉及到哈达玛积,这些门控制了信息的流动。 -
卷积神经网络(CNN):
在CNN中,哈达玛积用于元素级别的操作,例如在深度可分离卷积(Depthwise Separable Convolutions)中,通过对每个通道进行逐元素乘积来实现卷积操作,减少了计算量和参数量。 -
图神经网络(GNN):
在图神经网络中,哈达玛积用于节点特征的组合。例如,在图卷积网络(GCN)中,通过逐元素乘积来聚合邻居节点的特征,从而更新节点的表示。
【二】什么是NeRF(Neural-Radiance-Fields)技术?
NeRF(Neural Radiance Fields)技术主要用于生成高质量的三维场景渲染。NeRF技术通过使用神经网络来表示场景中的颜色和密度分布,从而能够生成从不同视角看到的高质量图像,在三维重建和新视图合成领域取得了显著的进展。以下是对 NeRF 技术的详细讲解:
基本概念
-
辐射场(Radiance Field):
- NeRF 表示场景的辐射场,这是一种三维空间中每个点的颜色和密度的函数。具体来说,辐射场定义了从某个点在某个方向上发出的光的颜色和强度。
-
核心模型:
- NeRF 使用一个多层感知器(MLP)作为神经网络。这个网络接受三维空间中的位置(x, y, z)和视角方向(θ, φ)作为输入,并输出该位置的颜色(RGB)和密度(σ)。
-
体积渲染:
- 通过体积渲染算法,从神经网络中采样不同位置的颜色和密度,合成最终的图像。体积渲染过程模拟了光线在三维场景中的传输和散射。
工作原理
NeRF 的工作原理可以分为以下几个步骤:
-
输入编码:
- NeRF 使用傅里叶特征编码(Fourier Feature Encoding)来对输入的三维坐标和视角方向进行高频特征变换,从而提高模型的表示能力。这种编码将低频的空间信息转换为高频特征,使得神经网络可以更好地学习到细节。
-
核心模型训练:
- 神经网络接受编码后的三维坐标和视角方向,输出该位置的颜色和密度。通过对比生成图像与实际图像之间的误差(如均方误差损失),调整神经网络的参数。
- 训练数据通常是从多个视角拍摄的二维图像,这些图像包含了场景的不同视角信息。
-
体积渲染:
- 对每条光线,从神经网络中采样多个点的颜色和密度,并通过体积渲染公式将这些值组合起来,生成光线上的像素颜色。
- 具体的体积渲染公式计算光线在经过场景中的每个点时的颜色贡献,并将这些贡献累加起来,形成最终的像素值。
应用场景
-
新视图合成:
- NeRF 可以从给定的几张二维图像生成新的视图,非常适合用于虚拟现实(VR)和增强现实(AR)应用。
-
3D 重建:
- NeRF 可以用于从二维图像重建高质量的三维模型,应用于影视、游戏和数字文化遗产保护等领域。
-
计算机图形学:
- 由于其生成高质量图像的能力,NeRF 在计算机图形学中也具有重要的应用价值。
优缺点
优点
- 高质量渲染:NeRF 可以生成非常逼真的图像,捕捉到细节和复杂的光照效果。
- 少量数据需求:与传统的3D重建方法相比,NeRF只需要较少的输入图像即可生成高质量的三维场景。
缺点
- 计算成本高:训练NeRF模型需要大量的计算资源和时间,尤其是对于高分辨率的场景。
- 实时性问题:目前,NeRF的实时渲染仍然是一个挑战,需要更多的优化和硬件支持。
Python编程基础
【一】什么是python的字符串格式化技术?
在Python中,字符串格式化是一项重要的技能,能帮助我们高效地生成和处理字符串。Python提供了多种字符串格式化的方法,包括旧式的百分号(%
)格式化、新式的str.format()
方法以及最新的f-string(格式化字符串字面量)。下面Rocky将详细讲解这些方法,让大家更好地理解。
1. 百分号(%)格式化
这是Python中最古老的字符串格式化方法,使用%
符号进行占位符替换。
基本用法:
name = "Alice"
age = 30
formatted_string = "Name: %s, Age: %d" % (name, age)
print(formatted_string) # 输出: Name: Alice, Age: 30
%s
用于字符串%d
用于整数%f
用于浮点数
控制浮点数精度:
pi = 3.14159
formatted_string = "Pi: %.2f" % pi
print(formatted_string) # 输出: Pi: 3.14
2. str.format()
方法
str.format()
方法更加灵活和强大,允许指定占位符的位置和格式。
基本用法:
name = "Alice"
age = 30
formatted_string = "Name: {}, Age: {}".format(name, age)
print(formatted_string) # 输出: Name: Alice, Age: 30
使用索引指定占位符的位置:
formatted_string = "Name: {0}, Age: {1}".format(name, age)
print(formatted_string) # 输出: Name: Alice, Age: 30
使用命名参数:
formatted_string = "Name: {name}, Age: {age}".format(name=name, age=age)
print(formatted_string) # 输出: Name: Alice, Age: 30
控制浮点数精度:
pi = 3.14159
formatted_string = "Pi: {:.2f}".format(pi)
print(formatted_string) # 输出: Pi: 3.14
3. f-string(格式化字符串字面量)
f-string是Python 3.6引入的一种新的格式化方法,提供了简洁和高效的方式。
基本用法:
name = "Alice"
age = 30
formatted_string = f"Name: {name}, Age: {age}"
print(formatted_string) # 输出: Name: Alice, Age: 30
控制浮点数精度:
pi = 3.14159
formatted_string = f"Pi: {pi:.2f}"
print(formatted_string) # 输出: Pi: 3.14
字符串格式化技术的应用场景
- 日志记录:格式化日志信息以便调试和分析。
- 数据输出:生成报告或导出数据。
- 用户界面:动态显示信息。
【二】Python中有哪些常用的设计模式?
Python作为一种多范式编程语言,支持多种设计模式。以下是AIGC、传统深度学习、自动驾驶领域中Python常用的设计模式:
创建型模式
-
单例模式(Singleton Pattern)
- 确保一个类只有一个实例,并提供一个全局访问点。
- 通俗例子:想象一个系统中有一个打印机管理器(Printer Manager),这个管理器负责管理打印任务。为了确保所有打印任务都能被统一管理,系统中只能有一个打印机管理器实例。
- 代码示例:
class PrinterManager: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(PrinterManager, cls).__new__(cls, *args, **kwargs) return cls._instance pm1 = PrinterManager() pm2 = PrinterManager() print(pm1 is pm2) # 输出: True
-
工厂方法模式(Factory Method Pattern)
- 定义一个创建对象的接口,但让子类决定实例化哪一个类。
- 通俗例子:想象一家新能源汽车工厂,它根据订单生产不同类型的汽车(如轿车、卡车、SUV)。每种汽车都是一个类,通过工厂方法决定创建哪种类型的汽车。
- 代码示例:
class Car: def drive(self): pass class Sedan(Car): def drive(self): return "Driving a sedan" class Truck(Car): def drive(self): return "Driving a truck" class CarFactory: def create_car(self, car_type): if car_type == "sedan": return Sedan() elif car_type == "truck": return Truck() factory = CarFactory() car = factory.create_car("sedan") print(car.drive()) # 输出: Driving a sedan
-
抽象工厂模式(Abstract Factory Pattern)
- 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 通俗例子:想象一个家具商店,它可以生产不同风格(现代风格、维多利亚风格)的家具。每种风格都有其特定的椅子和桌子,抽象工厂提供了创建这些家具的接口。
- 代码示例:
class Chair: def sit(self): pass class ModernChair(Chair): def sit(self): return "Sitting on a modern chair" class VictorianChair(Chair): def sit(self): return "Sitting on a victorian chair" class FurnitureFactory: def create_chair(self): pass class ModernFurnitureFactory(FurnitureFactory): def create_chair(self): return ModernChair() class VictorianFurnitureFactory(FurnitureFactory): def create_chair(self): return VictorianChair() factory = ModernFurnitureFactory() chair = factory.create_chair() print(chair.sit()) # 输出: Sitting on a modern chair
结构型模式
-
适配器模式(Adapter Pattern)
- 将一个类的接口转换为客户希望的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 通俗例子:想象你有一个老式的播放器,它只能播放CD,但你现在有一个现代的音乐库在你的手机上。你可以使用一个适配器,把手机的音乐格式转换成播放器能够播放的格式。
- 代码示例:
class OldPlayer: def play_cd(self): return "Playing music from CD" class NewPlayer: def play_music(self): return "Playing music from phone" class Adapter: def __init__(self, new_player): self.new_player = new_player def play_cd(self): return self.new_player.play_music() old_player = OldPlayer() print(old_player.play_cd()) # 输出: Playing music from CD new_player = NewPlayer() adapter = Adapter(new_player) print(adapter.play_cd()) # 输出: Playing music from phone
-
装饰器模式(Decorator Pattern)
- 动态地给对象添加一些职责。
- 通俗例子:想象我们在咖啡店点了一杯咖啡。你可以选择在咖啡上加牛奶、糖或者巧克力。这些添加物是装饰,装饰器模式允许我们动态地添加这些装饰。
- 代码示例:
class Coffee: def cost(self): return 5 class MilkDecorator: def __init__(self, coffee): self.coffee = coffee def cost(self): return self.coffee.cost() + 1 coffee = Coffee() print(coffee.cost()) # 输出: 5 milk_coffee = MilkDecorator(coffee) print(milk_coffee.cost()) # 输出: 6
-
代理模式(Proxy Pattern)
- 为其他对象提供一种代理以控制对这个对象的访问。
- 通俗例子:想象我们有一个银行账户。我们可以通过代理(如银行职员或ATM)来访问我们的账户,而不需要直接处理银行系统的复杂操作。
- 代码示例:
class BankAccount: def withdraw(self, amount): return f"Withdrew {amount} dollars" class ATMProxy: def __init__(self, bank_account): self.bank_account = bank_account def withdraw(self, amount): return self.bank_account.withdraw(amount) account = BankAccount() atm = ATMProxy(account) print(atm.withdraw(100)) # 输出: Withdrew 100 dollars
行为型模式
-
观察者模式(Observer Pattern)
- 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 通俗例子:想象我们订阅了一份杂志。每当有新一期杂志出版,杂志社就会通知我们。我们是观察者,杂志社是被观察者。
- 代码示例:
class Publisher: def __init__(self): self.subscribers = [] def subscribe(self, subscriber): self.subscribers.append(subscriber) def notify(self): for subscriber in self.subscribers: subscriber.update() class ConcreteSubscriber(Subscriber): def update(self): print("New magazine issue is out!") publisher = Publisher() subscriber = ConcreteSubscriber() publisher.subscribe(subscriber) publisher.notify() # 输出: New magazine issue is out!
-
策略模式(Strategy Pattern)
- 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
- 通俗例子:想象我们要去旅行,可以选择不同的交通方式(如开车、坐火车、坐飞机)。每种交通方式都是一个策略,策略模式允许我们在运行时选择不同的策略。
- 代码示例:
class TravelStrategy: def travel(self): pass class CarStrategy(TravelStrategy): def travel(self): return "Traveling by car" class TrainStrategy(TravelStrategy): def travel(self): return "Traveling by train" class TravelContext: def __init__(self, strategy): self.strategy = strategy def travel(self): return self.strategy.travel() context = TravelContext(CarStrategy()) print(context.travel()) # 输出: Traveling by car context.strategy = TrainStrategy() print(context.travel()) # 输出: Traveling by train
模型部署基础
【一】如何将AI模型缓存到内存中,这么做有什么好处?
在AI领域应用中,将AI模型缓存到内存中是一种提高模型推理性能的常见做法。缓存模型可以减少每次推理时模型加载的时间,尤其是在模型需要频繁访问或调用的场景中。下面Rocky将为大家演示如何将模型缓存到内存中,并在需要时加载到GPU进行推理,完成推理后再将其移回内存中的完整流程。
步骤 1: 初始化并缓存模型
首先,我们需要将预训练的AI模型加载到CPU的内存中。这可以确保在不使用GPU推理时,AI模型不会占用宝贵的GPU显存资源。
import torch
# 假设模型已经保存为 WeThinkIn.pth
model = torch.load('WeThinkIn.pth', map_location=torch.device('cpu'))
model.eval() # 设置模型为评估模式
步骤 2: 按需加载AI模型到GPU
当需要进行推理或计算时,可以将AI模型从CPU内存临时移动到GPU显存中来。这样做可以利用GPU的强大计算能力,提高AI模型的推理速度。
def load_model_to_gpu(model):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device) # 将模型加载到GPU
return model
步骤 3: 进行推理计算
在GPU上进行模型的推理计算。
def perform_inference(model, input_data):
input_data = input_data.to(model.device) # 确保输入数据也在同一设备
with torch.no_grad(): # 确保在推理模式下不计算梯度
output = model(input_data)
return output
步骤 4: 将AI模型移回CPU内存
推理计算完成后,可以选择将AI模型从GPU移回CP 内存,以释放GPU资源供其他任务使用。
def unload_model_from_gpu(model):
model.to('cpu') # 将模型移回 CPU
torch.cuda.empty_cache() # 清理 CUDA 缓存
完整的使用流程
将上述功能整合到一起,形成一个可以按需动态管理AI模型资源的流程。
model = torch.load('WeThinkIn.pth', map_location='cpu')
model.eval()
# 当需要使用模型时
model = load_model_to_gpu(model)
input_data = torch.randn(1, 3, 224, 224) # 示例输入
output = perform_inference(model, input_data)
model = unload_model_from_gpu(model)
注意事项
- 内存管理: 这种动态加载和卸载模型需要仔细管理内存,避免内存泄露。
- 性能考虑: 频繁地在CPU和GPU之间移动模型可能会影响任务整体性能。如果模型使用频率非常高,我们需要重新考虑是否每次都将AI模型移回CPU。
- 资源共享: 在多任务并行处理的环境下,合理分配GPU资源尤为重要。
通过这样的策略,我们可以有效地利用有限的GPU显存资源,在保证性能的同时,也确保了显存资源的最大化利用。
【二】什么是AI领域的延迟和吞吐量?
在AI领域中,延迟(Latency)和吞吐量(Throughput)是两个关键的性能指标,它们在评估系统的效率和响应能力方面起着至关重要的作用。理解并优化这两个指标对于提升AI系统的响应速度和处理能力至关重要。通过在不同应用场景中合理平衡延迟和吞吐量,可以实现更高效和更可靠的AI系统。以下是Rocky对这两个概念的详细解释及其在AI领域中的应用。
延迟 (Latency)
定义
延迟指的是从输入到输出所需的时间,通常表示为处理单个任务或请求所花费的时间。延迟可以分为以下几种类型:
- 网络延迟:数据在网络中传输的时间。
- 处理延迟:数据在系统中被处理所需的时间。
- 总延迟:包括所有类型延迟的总和,从请求发出到收到响应的总时间。
测量
延迟通常以毫秒(ms)为单位测量。测量延迟的方法包括:
- Ping 测试:测量数据包在网络中的往返时间。
- Benchmarking:使用基准测试工具测量系统处理特定任务的时间。
在AI领域中的应用
在AI领域中,延迟主要用于评估AI模型的推理耗时,尤其是在实时应用中,如AIGC、传统深度学习、自动驾驶等方向中。低延迟对于用户体验和AI系统性能至关重要。
吞吐量 (Throughput)
定义
吞吐量指的是AI系统在单位时间内处理的任务或请求的数量,通常表示为每秒处理的任务数(tasks per second 或 queries per second)。吞吐量反映了AI系统的整体处理能力。
测量
吞吐量通常以每秒处理的请求数量(RPS)或每秒处理的数据量(bps, MB/s)来表示。测量吞吐量的方法包括:
- Load Testing:在高负载下测试系统的最大处理能力。
- Stress Testing:测试系统在极限条件下的处理能力。
在AI领域中的应用
在AI领域中,吞吐量主要用于评估AI模型的训练和推理能力。高吞吐量意味着AI系统可以在单位时间内处理更多的数据或请求,这对于大规模数据处理和高并发请求的应用非常重要。
延迟和吞吐量的关系
-
平衡:在AI系统设计中,延迟和吞吐量往往需要平衡。例如,在一些实时应用中,优先考虑低延迟可能会降低吞吐量,而在批处理任务中,优先考虑高吞吐量可能会增加延迟。
-
资源利用:高吞吐量通常意味着更高的资源利用率,但也可能导致资源争用,从而增加延迟。相反,低延迟系统可能会有较低的资源利用率,但能提供更快速的响应。
-
优化策略:根据具体应用的需求,AI系统可以通过优化硬件配置、调整算法、并行处理等方法来降低延迟和提高吞吐量。例如,使用更快的处理器和更高效的算法可以同时改善延迟和吞吐量。
实际示例
-
图像分类模型:
- 延迟:测量单张图像从输入到分类结果输出的时间。
- 吞吐量:测量每秒钟可以处理的图像数量。
-
视频流处理:
- 延迟:测量每帧视频从捕获到显示所需的时间。
- 吞吐量:测量每秒可以处理的帧数。
-
自然语言处理(NLP):
- 延迟:测量从文本输入到生成翻译结果的时间。
- 吞吐量:测量每秒可以处理的句子数量。
计算机基础
Rocky从工业界、应用界、竞赛界以及学术界角度出发,总结沉淀AI行业中需要用到的实用计算机基础知识,不仅能在面试中帮助到我们,还能让我们在日常工作中提高效率。
【一】Linux中的tail命令使用大全
tail
命令是一个非常有用的命令行工具,用于查看文件的末尾部分,尤其是在AIGC、传统深度学习、自动驾驶领域中查看日志文件时。下面是 tail
命令在 Ubuntu(以及其他类Linux系统)中的各种用法及其选项的详细说明。
基本用法
-
查看文件的最后 10 行(默认行为):
tail /path/to/your/file
-
指定行数:使用
-n
选项来指定要查看的行数。tail -n 20 /path/to/your/file
或者使用简短的
-20
形式:tail -20 /path/to/your/file
实时监控文件(AI行业高价值命令)
-
持续跟踪文件更新:使用
-f
选项,tail
会显示文件的最后几行并在文件有新内容追加时,实时显示新增内容。这对于监控实时日志非常有用。tail -f /path/to/your/file
-
结合
-n
和-f
:可以结合-n
和-f
选项,先显示文件的最后几行并持续跟踪文件更新。tail -n 20 -f /path/to/your/file
多文件查看
- 查看多个文件的尾部:可以同时查看多个文件的尾部,
tail
会在输出中显示文件名作为标识。tail -n 20 /path/to/your/file1 /path/to/your/file2
显示字节数
- 按字节显示:使用
-c
选项按字节显示文件的末尾部分。tail -c 100 /path/to/your/file
持续监控文件变化并进行高级操作
-
附加模式:使用
--follow
选项的name
参数,可以在文件重命名或旋转(如日志文件轮转)后继续跟踪。tail --follow=name /path/to/your/file
-
与其他命令结合使用:结合管道和其他命令进行更复杂的操作。例如,过滤实时日志输出中的某些关键字:
tail -f /path/to/your/file | grep "keyword"
高级选项
-
从特定行开始显示:使用
+
号表示从文件的第几行开始显示。tail -n +5 /path/to/your/file
-
使用
--max-unchanged-stats
选项:设置 tail 在文件未变化时检查文件变化的最大次数。tail --max-unchanged-stats=5 -f /path/to/your/file
通过这些命令和选项,我们可以高效地查看和监控文件内容,特别是日志文件,帮助我们在AIGC、传统深度学习、自动驾驶等领域更好地进行系统管理、调试和故障排除中的获取和分析信息。
【二】Linux中有哪些常用的查看文件夹占用空间的命令?
在AIGC、传统深度学习、自动驾驶领域,我们经常需要进行大规模的数据整理与迁移等工作,所以掌握Linux系统中的不同文件夹的占用空间,对我们日常的工作能够降本增效。下面是Linux系统中常用的查看文件夹占用空间的命令:
在 Linux 中,有多种命令可以用来查看文件夹占用的空间。以下是几种常用的方法和工具:
1. du
(Disk Usage)
du
是一个非常强大的命令,用于检查文件和目录的磁盘使用情况。它的基本用法和常见选项如下:
查看当前目录下的每个文件夹的大小
du -h --max-depth=1
-h
:以人类可读的格式显示(例如:K,M,G)。--max-depth=1
:限制显示深度为1层,只显示当前目录下的文件夹大小。
查看特定目录下的每个文件夹的大小
du -h --max-depth=1 /path/to/directory
只显示总大小
du -sh /path/to/directory
-s
:只显示总计。
在 Ubuntu 系统中,你可以使用 du
(disk usage)命令来查看每个文件夹占用的磁盘空间。以下是一些常见的方法和选项,可以帮助你获取所需的信息。
使用 du
命令查看每个文件夹的占用空间
查看当前目录下的每个文件夹的大小
du -h --max-depth=1
-h
:以人类可读的格式显示(例如:K,M,G)。--max-depth=1
:仅显示当前目录下的文件夹大小。
查看特定目录下的每个文件夹的大小
例如,要查看 /var
目录下每个文件夹的大小,可以使用:
du -h --max-depth=1 /var
查看所有子目录的大小
如果你想查看所有子目录的详细大小,可以省略 --max-depth
选项:
du -h /var
只显示总大小
如果你只想查看某个目录的总大小,可以使用 -s
选项:
du -sh /var
结合 sort
命令查看占用空间最大的文件夹
我们可以结合 sort
命令查看占用空间最大的文件夹:
du -h --max-depth=1 /home | sort -hr
sort -hr
:根据大小进行降序排序。
示例解释
假设我们在 /home
目录下运行 du -h --max-depth=1
,输出可能如下所示:
4.0K ./WeThinkIn
16K ./Documents
3.1G ./Downloads
8.0K ./Music
24K ./Pictures
5.2M ./Videos
3.2G .
这里每一行表示每个子目录的大小,最后一行 3.2G .
表示当前目录(即 /home
目录)的总大小。
2. ncdu
(NCurses Disk Usage)
ncdu
是一个基于文本的磁盘使用分析工具,提供了交互式的界面。
安装 ncdu
sudo apt install ncdu # 对于Debian/Ubuntu
sudo yum install ncdu # 对于RHEL/CentOS
使用 ncdu
ncdu /path/to/directory
3. df
(Disk Free)
虽然 df
主要用于显示文件系统的总的磁盘空间使用情况,但也可以用来查看特定挂载点的使用情况。
查看所有文件系统的使用情况
df -h
-h
:以人类可读的格式显示。
查看特定目录的文件系统使用情况
df -h /path/to/directory
4. duf
(Disk Usage/Free Utility)
duf
是一个现代的磁盘使用情况查看工具,具有彩色输出和交互式界面。
安装 duf
sudo apt install duf # 对于Debian/Ubuntu
sudo yum install duf # 对于RHEL/CentOS
使用 duf
duf
5. ls
和 find
配合使用
通过组合 ls
和 find
命令,可以获取每个文件夹和文件的大小。
查看当前目录下所有文件和文件夹的大小
find . -type f -exec ls -lh {} + | awk '{print $9 ": " $5}'
6. tree
命令
tree
可以以树状结构显示目录内容,并提供每个文件和目录的大小。
安装 tree
sudo apt install tree # 对于Debian/Ubuntu
sudo yum install tree # 对于RHEL/CentOS
使用 tree
tree -h /path/to/directory
-h
:以人类可读的格式显示大小。
开放性问题
Rocky从工业界、应用界、竞赛界以及学术界角度出发,思考总结AI行业的一些开放性问题,这些问题不仅能够用于面试官的提问,也可以用作面试者的提问,在面试的最后阶段让面试双方进入更深入的探讨与交流。
与此同时,这些开放性问题也是贯穿我们职业生涯的本质问题,需要我们持续的思考感悟。这些问题没有标准答案,Rocky相信大家心中都有自己对于AI行业的认知与判断,欢迎大家在留言区分享与评论。
【一】AI行业现阶段以及未来能够落地商用的领域有哪些?
根据目前AI行业的发展趋势来看,Rocky认为现阶段近10-20年左右的时间,AI行业能够落地商用的领域包括:
- AIGC大方向
- 传统深度学习大方向
- 自动驾驶大方向
在未来,AI行业很有可能迸发出更加繁荣的活力,在以下的大方向中会有新的红利与机遇:
- 元宇宙
- AGI
【二】如何给一个完全没有接触过AIGC的人介绍AIGC?
Rocky认为这是一个非常有价值的问题,因为现在AI行业已经进入AIGC时代,同时AIGC又是一个破圈式繁荣的时代,所以如何理解好AIGC的内涵,并且深入浅出的向传统深度学习领域的从业者、高校的初学者以及各行各业的AIGC应用者们介绍好AIGC,成为了AIGC领域从业者的必修课。
推荐阅读
1、加入AIGCmagic社区知识星球
AIGCmagic社区知识星球不同于市面上其他的AI知识星球,AIGCmagic社区知识星球是国内首个以AIGC全栈技术与商业变现为主线的学习交流平台,涉及AI绘画、AI视频、ChatGPT等大模型、AI多模态、数字人、全行业AIGC赋能等50+应用方向,内部包含海量学习资源、专业问答、前沿资讯、内推招聘、AIGC模型、AIGC数据集和源码等。
那该如何加入星球呢?很简单,我们只需要扫下方的二维码即可。知识星球原价:299元/年,前200名限量活动价,终身优惠只需199元/年。大家只需要扫描下面的星球优惠卷即可享受初始居民的最大优惠:
2、Stable Diffusion XL核心基础知识,从0到1搭建使用Stable Diffusion XL进行AI绘画,从0到1上手使用Stable Diffusion XL训练自己的AI绘画模型,AI绘画领域的未来发展等全维度解析文章正式发布
码字不易,欢迎大家多多点赞:
Stable Diffusion XL文章地址:https://zhuanlan.zhihu.com/p/643420260
3、Stable DiffusionV1-V2核心原理,核心基础知识,网络结构,经典应用场景,从0到1搭建使用Stable Diffusion进行AI绘画,从0到1上手使用Stable Diffusion训练自己的AI绘画模型,Stable Diffusion性能优化等全维度解析文章正式发布
码字不易,欢迎大家多多点赞:
Stable Diffusion文章地址:https://zhuanlan.zhihu.com/p/632809634
4、ControlNet核心基础知识,核心网络结构,从0到1使用ControlNet进行AI绘画,从0到1上手构建ControlNet高级应用等全维度解析文章正式发布
码字不易,欢迎大家多多点赞:
ControlNet文章地址:https://zhuanlan.zhihu.com/p/660924126
5、LoRA系列模型核心基础知识,从0到1使用LoRA模型进行AI绘画,从0到1上手训练自己的LoRA模型,LoRA变体模型介绍,优质LoRA推荐等全维度解析文章正式发布
码字不易,欢迎大家多多点赞:
LoRA文章地址:https://zhuanlan.zhihu.com/p/639229126
6、最全面的AIGC面经《手把手教你成为AIGC算法工程师,斩获AIGC算法offer!(2024年版)》文章正式发布
码字不易,欢迎大家多多点赞:
AIGC面经文章地址:https://zhuanlan.zhihu.com/p/651076114
7、10万字大汇总《“三年面试五年模拟”之算法工程师的求职面试“独孤九剑”秘籍》文章正式发布
码字不易,欢迎大家多多点赞:
算法工程师三年面试五年模拟文章地址:https://zhuanlan.zhihu.com/p/545374303
《三年面试五年模拟》github项目地址(希望大家能给个star):https://github.com/WeThinkIn/Interview-for-Algorithm-Engineer
8、Stable Diffusion WebUI、ComfyUI、Fooocus三大主流AI绘画框架核心知识,从0到1搭建AI绘画框架,从0到1使用AI绘画框架的保姆级教程,深入浅出介绍AI绘画框架的各模块功能,深入浅出介绍AI绘画框架的高阶用法等全维度解析文章正式发布
码字不易,欢迎大家多多点赞:
AI绘画框架文章地址:https://zhuanlan.zhihu.com/p/673439761
9、其他
Rocky将YOLOv1-v7全系列大解析文章也制作成相应的pdf版本,大家可以关注公众号WeThinkIn,并在后台 【精华干货】菜单或者回复关键词“YOLO” 进行取用。
Rocky一直在运营技术交流群(WeThinkIn-技术交流群),这个群的初心主要聚焦于技术话题的讨论与学习,包括但不限于算法,开发,竞赛,科研以及工作求职等。群里有很多人工智能行业的大牛,欢迎大家入群一起学习交流~(请添加小助手微信Jarvis8866,拉你进群~)