最近感觉记性变得有点差,很多方法的使用经常记不住,虽然说现在已经是llm后时代了,但是感觉很多代码如果不是自己写的话会有一种无力感(笑),故在此记录一下pytorch常用的一些方法(其实也包括python方法,笔者的python基础也是一坨。。)

首先就是一些常用的创建张量的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import torch
# 个人习惯里面传入列表来创建张量
tensor1=torch.tensor()
# 按照一定的序列创建张量,和range用法差不多(比如输入3,10就会创建出一个(7,)的张量)
torch.arange(begin,end,step)
# 创建固定大小和值的张量
torch.full(size,fill_value)
# 创建全0张量
torch.zeros(size)
# 创建全1张量
torch.ones(size)
#通过已有张量创建全0或者全1张量
torch.ones_like(input_tensor)
torch.zeros_like(input_tensor)

当然了,我们在写模型和搭建训练pipeline时不止要创造tensor,还要对其进行各种操作,这里我也会列出自己写模型中遇到的常见操作:

先从各种属性讲起吧

1
2
3
4
5
6
# 访问当前张量所在设备(默认是在CPU上)
tensor.device
# 访问当前张量的类型(pytorch中默认为torch.float32)
tensor.dtype
# 访问当前张量的形状(返回一个元组)
tensor.shape

对张量变换的各种方法(大部分都是numpy中已有的方法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 迁移设备和转换类型
tensor.to(device or dtype)
# 分离张量,在多头注意力中经常使用
tensor.split(split_num,dim=dim)->torch.Tensor
'''
args:
split_num->分离的数量
dim->拆分的维度
'''
# 获取张量某一个维度的大小
tensor.size(dim)
# 改变张量的形状(一般都有参数keepdim)
tensor.transpose(size)
# 注意:此方法下张量元素在内存中必须是连续的,最好在使用之前用contiguous()进行重构
tensor.view(size)
tensor.reshape(size)
# 使用cat或者stack或者用了sum和mean之后我们往往不希望张量的维度发生变化(既希望保留原有的维度即使为1)
#保持原有维度
tensor.unsequeeze(dim)
#消除大小为1的维度
tensor.sequeeze(dim)
# 如果张量是二维的情况下可以直接对其进行转置
tensor.T
# 张量的拼接(两者都可以使用)
tensor.cat(size,dim,device)
tensor.stack(size,dim,device)

数学方法:

pytorch中有很多数学函数可以直接使用,与numpy不同的是需要输入张量

1
2
3
4
5
6
7
8
9
# 这里不一一举例了
torch.exp()
torch.log()
torch.sin()
# 这里特别介绍两个可能会使用的方法
# 计算两个向量的外积,所以输入必须是一维张量
torch.outer(tensor,tensor)
# 计算根号倒数
torch.rsqrt(tensor,dim)

其余常用方法:

pytorch中还提供了其它用于张量操作的方法:

1
2
3
4
5
6
7
8
# 对张量进行排列(指定某个维度以及是否降序),返回原索引和排序后的元素
torch.sort(tensor,descending=False,dim)
# 获取张量的累计和
torch.cumsum(tensor,dim)
# 采样函数(返回一个张量)
torch.multinomial(tensor,num_sample)
# 映射函数,根据当前索引映射回未排序之前的序列索引中,一般和torch.sort配合使用,返回一个索引
torch.gather(index_tensor,dim,index_current)

一些python中的记忆点:

1
2
3
4
5
6
7
8
# 断言表达式,后面接的一般是布尔表达式(可加上报错提示),如果为真才会继续运行下去,否则抛出AssertionError以及报错信息(如果有)
assert
# 这种和普通的""区别在于会取消转义字符,一般用在正则表达式中
r""
# 多行字符串(如果字符串长度实在太大时使用)
"""
你好呀
"""

使用命令行参数的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import argparse

def parse_args():
parser=argparse.ArgumentParser(
description=""
)

parser.add_argument(
"--argument_name" ,
type=,
default=,
help=""
)

return parser.parse_args()

args=parse_args()
# 然后就可以直接使用args里面的参数了

正则表达式的一些用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import regex
PAT="" # 匹配模式
pattern=regex.complie(PAT) # 编译,之后使用不用每次都解析表达式
text=""
for match in pattern.finditer(text):
# 获得整个匹配结果,相当于str=match.group()
str=match.group(0)
# 获得捕获组1
str=match.group(1)
# 获得所有匹配结果,返回列表
strs=pattern.findall(text)
# 将整个文本中的匹配结果替换为replace_str,return new_text
pattern.sub(replace_str,text)
# 作用同上,同时返回匹配到的总个数,return (new_text,num_match)
pattern.subn(replace_str,text)

python中字符串的用法:

1
2
3
4
5
6
7
split(sub_str) # 结果不包括sub_str,返回一个列表,包含分离的结果
find(sub_str) # 找子串,如果找到了返回第一处的index,没有返回-1
strip(sub_str) # 以sub_str里面的字符为标准,将字符串中所有sub_str含有的字符全部消除,返回新字符串
sub_str.join(str_iterator) # 使用sub_str将所有str合成一个字符串,其中str_iterator是一个含字符串元素的迭代器
endswith(substr) # 返回布尔值,如果以substr结尾返回True
isalnum()
isalpha()

易错点:

1
list() #如果里面放入可迭代对象,会将可迭代对象全部解包,然后变成列表元素,比如放入一个元组,不是元组作为元素,而是将整个元组解包放入