torch.nn.Parameter继承torch.Tensor,其作用将一个不可训练的类型为Tensor的参数转化为可训练的类型为parameter的参数,并将这个参数绑定到module里面,成为module中可训练的参数。
torch.nn.Parameter(Tensor data, bool requires_grad)
其中:data为传入Tensor类型参数,requires_grad默认值为True,表示可训练,False表示不可训练。
pytorch中torch.ones()
torch.ones(*sizes, out=None) → Tensor
返回一个全为1 的张量,形状由可变参数sizes定义。
pytorch中sum()函数x.sum(),第0个维度是行,第1个维度是列
说明文档中
torch.sum
在给定维度的情况下,返回每一行的和。
如果keepdim=True,那么输出和输出的形状是相同的,除了dim维度变为1
例子如下:
x是一个五行三列的tensor
对x的每一行进行求和,结果应该是五行一列,形状还是2个维度,所以keepdim=True,因为列变成了1,所以dim=1,合并起来:x.sum(dim=1,keepdim=True)
对每一列进行求和,输出的结果应该是一行三列,形状还是两个维度,keepdim=True,这里行变成了1,所以dim=0,合并起来:x.sum(dim=0,keepdim=True)
import torch x = torch.rand(5,3) print(x) y1 = x.sum(dim=1, keepdim=True) print(y1) y2 = x.sum(dim=1) print(y2) y3 = x.sum(dim=0, keepdim=True) print(y3) y4 = x.sum(dim=0) print(y4) y5 = x.sum(dim=[0,1]) print(y5)
例如:
X = torch.tensor([[1, 2, 3], [4, 5, 6]]) print(X.sum(dim=0, keepdim=True)) # dim为0,按照相同的列求和,并在结果中保留列特征 print(X.sum(dim=1, keepdim=True)) # dim为1,按照相同的行求和,并在结果中保留行特征 print(X.sum(dim=0, keepdim=False)) # dim为0,按照相同的列求和,不在结果中保留列特征 print(X.sum(dim=1, keepdim=False)) # dim为1,按照相同的行求和,不在结果中保留行特征
结果:
可以简化着来看,已经给定的张量为23
假设对张量的每一行进行求和,则求和后的张量应为21,所以dim=1表示第二个元素。
如果对张量的每一列进行求和,求和后的张量应该为1*3,所以dim=0表示第一个元素。
如果keepdim=True,则求和后的应该还是为张量,保留维度。
自动填充函数
import torch
from transformers import BertTokenizer
from torch.nn.utils.rnn import pad_sequence,pack_padded_sequence,pack_sequence,pad_packed_sequence
if __name__ == '__main__':
texts = [
"你好我是一个NLP工程师",
"中国人",
"我要好好工作努力挣钱买房买车",
"你",
"老婆老婆老婆我爱你"
]
tokenizer = BertTokenizer.from_pretrained('pretrained_models/chinese-bert-wwm-ext')
# datas = [ torch.tensor(tokenizer(text)['input_ids'],dtype=torch.long) for text in texts]
datas = [tokenizer(text)['input_ids'] for text in texts]
for data in datas:
print(data)
datas = [torch.tensor(data,dtype=torch.long) for data in datas]
print(datas)
pad_datas = pad_sequence(datas,batch_first=True,padding_value=0)
print(pad_datas.shape)
print(pad_datas)
结果中长度效果16的,就自动的填充了0,使得pad_datas成为等长的,可以组成batch,输入到模型中进行并行计算。
对经过padded_sequence进行压缩。经过padding后的tensor会含有很多无意义的padding_value,它对模型的效果最终有一定的影响,为了完全消除这个影响,就需要把这些无意义的padding_value进行压缩。
例子:
if __name__ == '__main__':
texts = [
"你好我是一个NLP工程师",
"中国人",
"我要好好工作努力挣钱买房买车",
"你",
"老婆老婆老婆我爱你"
]
tokenizer = BertTokenizer.from_pretrained('pretrained_models/chinese-bert-wwm-ext')
# datas = [ torch.tensor(tokenizer(text)['input_ids'],dtype=torch.long) for text in texts]
datas = [tokenizer(text)['input_ids'] for text in texts]
lengths = [ len(data) for data in datas]
for data in datas:
print(data)
datas = [torch.tensor(data,dtype=torch.long) for data in datas]
print('datas',datas)
pad_datas = pad_sequence(datas,batch_first=True,padding_value=0)
print('pad_datas.shape',pad_datas.shape)
print('pad_datas',pad_datas)
pack_pad_datas = pack_padded_sequence(input=pad_datas,lengths = lengths ,batch_first=True, enforce_sorted=False)
print('pack_pad_datas',pack_pad_datas)
结果:
pack_pad_datas PackedSequence(data=tensor([ 101, 101, 101, 101, 101, 2769, 872, 5439, 704, 872,
6206, 1962, 2038, 1744, 102, 1962, 2769, 5439, 782, 1962,
3221, 2038, 102, 2339, 671, 5439, 868, 702, 2038, 1222,
156, 2769, 1213, 10986, 4263, 2914, 2339, 872, 7178, 4923,
102, 743, 2360, 2791, 102, 743, 6756, 102]), batch_sizes=tensor([5, 5, 5, 4, 4, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 1]), sorted_indices=tensor([2, 0, 4, 1, 3]), unsorted_indices=tensor([1, 3, 0, 4, 2]))
pytorch中pad_packed_sequence函数
对已经压缩过的数据进行填充恢复,联合pack_padded_sequence()来看,它们之间应该是互为逆操作的。
pad_datas = pad_sequence(datas,batch_first=True,padding_value=0)
print('pad_datas',pad_datas)
pack_pad_datas = pack_padded_sequence(input=pad_datas,lengths = lengths ,batch_first=True, enforce_sorted=False)
print('pack_pad_datas',pack_pad_datas)
origin_data = pad_packed_sequence(sequence=pack_pad_datas,batch_first=True,padding_value=0)
print('origin_data',origin_data)
经过pack_padded_sequence()压缩后的数据输入到RNN模型中,得到的结果也是没有padding_vaule的,维度和之前的那些没有压缩的数据对不齐,后续的操作就不好处理,则需要逆向填充回来对齐后,方便后续的操作。
batch_first=True
PyTorch中对于不同的网络层,输入的维度虽然不同,但是通常输入的第一个维度都是batch_size,比如torch.nn.Linear的输入(batch_size,in_features),torch.nn.Conv2d的输入(batch_size, C, H, W)。
RNN的输入却是(seq_len, batch_size, input_size),batch_size位于第二维度!你可以将batch_size和序列长度seq_len对换位置,此时只需要令batch_first=True。
初始化一个全连接神经网络。
import torch import torch.nn as nn # 首先初始化一个全连接神经网络 full_connected = nn.Linear(12, 15) # 输入 input = torch.randn(5, 12) # 输出 output = full_connected(input) print(output.shape) print(full_connected.weight.shape) print(full_connected.bias.shape) # 结果展示 # output.shape:torch.Size([5, 15]) # full_connected.weight.shape: torch.Size([15, 12]) # full_connected.bias.shape: torch.Size([15])pytorch中torch.Tensor和torch.tensor的区别
torch.Tensor()是Python类,更明确的说,是默认张量类型torch.FloatTensor()的别名,torch.Tensor([1,2]) 会调用Tensor类的构造函数__init__,生成单精度浮点类型的张量。
>>> a=torch.Tensor([1,2]) >>> a.type() 'torch.FloatTensor'
torch.tensor()仅仅是Python的函数,函数原型是:torch.tensor(data, dtype=None, device=None, requires_grad=False),torch.tensor()可以从data中的数据部分做拷贝(而不是直接引用),根据原始数据类型生成相应的torch.LongTensor,torch.FloatTensor,torch.DoubleTensor。
>>> a = torch.tensor([1, 2]) >>> a.type() 'torch.LongTensor'
>>> a = torch.tensor([1., 2.]) >>> a.type() 'torch.FloatTensor'
>>> a = np.zeros(2, dtype=np.float64) >>> a = torch.tensor(a) >>> a.type() torch.DoubleTensorpytorch中squeeze()函数
降维:torch.squeeze(input, dim=None, out=None)
函数功能:去除size为1的维度,包括行和列。当维度大于等于2时,squeeze()无作用。
当给定dim时,那么挤压操作只在给定维度上。即若tensor.size(dim) = 1,则去掉该维度。
其中squeeze(0)代表若第一维度值为1则去除第一维度
squeeze(1)代表若第二维度值为1则去除第二维度
-1,去除最后维度值为1的维度
当不给定dim时,将输入张量形状中的1 去除并返回。 如果输入是形如(A×1×B×1×C×1×D)(A×1×B×1×C×1×D),那么输出形状就为: (A×B×C×D)(A×B×C×D)
输入形状为: (A×1×B)(A×1×B), squeeze(input, 0) 将会保持张量不变,只有用 squeeze(input, 1),形状会变成 (A×B)(A×B)
a = torch.Tensor(1,3) >> tensor([[-1.37,4.56,-3.57]]) print a.squeeze(0) #第一个维度大小确实是1,所以可以去除 >> tensor([-1.37,4.56,-3.57]) print a.squeeze(1) ##第二个维度大小是3,所以不能去除 >> tensor([[-1.37,4.56,-3.57]]) #例子2 b = torch.Tensor(2,3) print b >> tensor([[-3.17,3.09,1.43], [0.00,0.00,0.00]]) print b.squeeze(0)##第一个维度大小不是1,所以不能去除 >> tensor([[-3.17,3.09,1.43], [0.00,0.00,0.00]]) print b.squeeze(1) ##第二个维度大小是3,所以不能去除 >> tensor([[-3.17,3.09,1.43], [0.00,0.00,0.00]]) #例子3 c = torch.Tensor(3,1) print c >> tensor([[-3.54], [3.09], [0.00]]) print c.squeeze(0)##第一个维度大小不是1,所以不能去除 >> tensor([[-3.54], [3.09], [0.00]]) print c.squeeze(1)#第二个维度大小确实是1,所以可以去除 >> tensor([-3.54,3.09,0.00])pytorch中unsqueeze()函数
增维: torch.unsqueeze(input, dim, out=None)
增加大小为1的维度,也就是返回一个新的张量,对输入的指定位置插入维度 1且必须指明维度。
x = torch.unsqueeze(x, 3) # 在第3个维度上扩展
0:最粗粒度的方向,在第1维插入一个维度
1:在第2维插入一个维度
2:最细粒度的方向,在第3维插入一个维度
-3:在倒数第3维插入一个维度
import torch x = torch.ones(4) print(x) print(x.size()) y = torch.unsqueeze(x, 0) print(y) print(y.size()) z = torch.unsqueeze(x, 1) print(z) print(z.size())
例子:
import torch x = torch.ones(3,4) print(x) print(x.size()) y = torch.unsqueeze(x, 0) print(y) print(y.size()) z = torch.unsqueeze(x, 1) print(z) print(z.size()) z1 = torch.unsqueeze(x, 2) print(z1) print(z1.size())
结果:
tensor([[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]])
torch.Size([3, 4])
tensor([[[1., 1., 1., 1.],
[1., 1., 1., 1.],
[1., 1., 1., 1.]]])
torch.Size([1, 3, 4])
tensor([[[1., 1., 1., 1.]],
[[1., 1., 1., 1.]],
[[1., 1., 1., 1.]]])
torch.Size([3, 1, 4])
tensor([[[1.],
[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.],
[1.]]])
torch.Size([3, 4, 1])
例子:
import torch x = torch.ones(3,4,3) print(x) print(x.size()) y = torch.unsqueeze(x, 0) print(y) print(y.size()) z = torch.unsqueeze(x, 1) print(z) print(z.size()) z1 = torch.unsqueeze(x, 2) print(z1) print(z1.size()) z2 = torch.unsqueeze(x, 3) print(z2) print(z2.size())
输出的结果为:
结果为:
tensor([[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]],
[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]],
[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]])
torch.Size([3, 4, 3])
tensor([[[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]],
[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]],
[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]]])
torch.Size([1, 3, 4, 3])
tensor([[[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]],
[[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]],
[[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]]])
torch.Size([3, 1, 4, 3])
tensor([[[[1., 1., 1.]],
[[1., 1., 1.]],
[[1., 1., 1.]],
[[1., 1., 1.]]],
[[[1., 1., 1.]],
[[1., 1., 1.]],
[[1., 1., 1.]],
[[1., 1., 1.]]],
[[[1., 1., 1.]],
[[1., 1., 1.]],
[[1., 1., 1.]],
[[1., 1., 1.]]]])
torch.Size([3, 4, 1, 3])
tensor([[[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]]],
[[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]]],
[[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]],
[[1.],
[1.],
[1.]]]])
torch.Size([3, 4, 3, 1])
进程已结束,退出代码为 0
pytorch中expand()函数
参考:【Pytorch】expand()用法==》扩展某个维度
只能在第0维扩展一个维数,比如原来是是(1,3,4)》(2,1,3,4),而在其他维度扩展不可以(1,3,4)》(1,2,3,4)【错误】
如果不增加维数,只是增加维度,要增加的原维度必须是1才可以在该维度增加维度,其他值均不可以。
import torch
#1
x = torch.randn(2, 1, 1)**#为1可以扩展为3和4**
x = x.expand(2, 3, 4)
print('x :', x.size())
>>> x : torch.Size([2, 3, 4])
#2
**#扩展一个新的维度必须在最前面,否则会报错**
x = x.expand(2, 3, 4, 6)
>>> RuntimeError: The expanded size of the tensor (3) must match the existing size (2) at non-singleton dimension 1.
x = x.expand(6, 2, 3, 4)
>>> x : torch.Size([6, 2, 3, 4])
#3
**#某一个维度为-1表示不改变该维度的大小**
x = x.expand(6, -1, -1, -1)
>>> x : torch.Size([6, 2, 1, 1])
pytorch中to(device)
.to(device) 可以指定CPU 或者GPU。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # 单GPU或者CPU
model.to(device)
#如果是多GPU
if torch.cuda.device_count() > 1:
model = nn.DataParallel(model,device_ids=[0,1,2])
model.to(device)
.cuda() 只能指定GPU
#指定某个GPU os.environ['CUDA_VISIBLE_DEVICE']='1' model.cuda() #如果是多GPU os.environment['CUDA_VISIBLE_DEVICES'] = '0,1,2,3' device_ids = [0,1,2,3] net = torch.nn.Dataparallel(net, device_ids =device_ids) net = torch.nn.Dataparallel(net) # 默认使用所有的device_ids net = net.cuda()



