Pytorch 记录

1.pytorch中的索引 index_select(x, dim, indices)
dim代表维度,indices是筛选的索引序号,一般indices传入的是torch.LongTensor([1,2])这种类型。见pytorch的切片

2..data是从Variable获取底层Tensor的主要方式。

3.优化器Optimizer都实现了step()方法来对所有的参数进行更新。
Loss.backward()反向传播 #This call will compute the gradient of loss with respect to all Tensors with requires_grad=True.
Optimizer.step() 更新参数

4.torch.squeeze(input, dim=None, out=None)
将某一方向全部相同数据压缩掉,想想一下,x、y、z是三维的,如果z全为0,则可转化为二维。

torch.Tensor.view()会将原有数据重新分配为一个新的张量,同reshape()
如果有一个维度的大小用-1代替,那么该函数就会根据张量总元素的个数和其他个维度的元素个数自动计算这个用-1指定的维度的大小。

x = torch.randn(2, 4)
#1.5600 -1.6180 -2.0366  2.7115
 #0.8415 -1.0103 -0.4793  1.5734
#[torch.FloatTensor of size 2x4]
y = x.view(4,2)
print y

# 输出如下
 1.5600 -1.6180
-2.0366  2.7115
 0.8415 -1.0103
-0.4793  1.5734
[torch.FloatTensor of size 4x2]

5.和numpy之间的转换:from_numpy() numpy()
Pytorch变量类型转换

6.torch.nn.Embedding
官方文档说明:


Embedding

参考:word_embeddings_tutorial.以下是笔记以下是笔记以下是笔记(重要的话说三遍)
word embeddings are a representation of the semantics of a word, efficiently encoding semantic information that might be relevant to the task at hand
Central to the idea of deep learning is that the neural network learns representations of the features, rather than requiring the programmer to design them herself. So why not just let the word embeddings be parameters in our model, and then be updated during training? This is exactly what we will do.
Similar to how we defined a unique index for each word when making one-hot vectors, we also need to define an index for each word when using embeddings. These will be keys into a lookup table.
To index into this table, you must use torch.LongTensor (since the indices are integers, not floats).
我们在使用它的时候,需要建立一个语料中所有词的词典,使用one-hot形式表示所有的的词。
在实例化embedding类的对象时,需要传入的参数为the vocabulary size, and the dimensionality of the embeddings.(词典中的单词个数,嵌入的词的维度,padding_idx),其中,如果给了padding_idx(int型),那么就是使用padding_idx的值进行嵌入。
使用时,传入的input的值应该为 torch.LongTensor,1⃣️要么用torch.tensor()里指定dtype=torch.long2⃣️要么torch.LongTensor([张量])3⃣️要么可以使用data.long()转换一下.

2019.1.23踩坑:

Traceback (most recent call last):
  File "/Users/yumi/Documents/Code/pytorch_related/classifier/CNN+pooling/code/CNN.py", line 112, in <module>
    pred = model(inputs)
  File "/anaconda3/python.app/Contents/lib/python3.6/site-packages/torch/nn/modules/module.py", line 489, in __call__
    result = self.forward(*input, **kwargs)
  File "/Users/yumi/Documents/Code/pytorch_related/classifier/CNN+pooling/code/CNN.py", line 89, in forward
    out = self.embedded(x)
  File "/anaconda3/python.app/Contents/lib/python3.6/site-packages/torch/nn/modules/module.py", line 489, in __call__
    result = self.forward(*input, **kwargs)
  File "/anaconda3/python.app/Contents/lib/python3.6/site-packages/torch/nn/modules/sparse.py", line 118, in forward
    self.norm_type, self.scale_grad_by_freq, self.sparse)
  File "/anaconda3/python.app/Contents/lib/python3.6/site-packages/torch/nn/functional.py", line 1454, in embedding
    return torch.embedding(weight, input, padding_idx, scale_grad_by_freq, sparse)
RuntimeError: index out of range at /Users/administrator/nightlies/pytorch-1.0.0/wheel_build_dirs/conda_3.6/conda/conda-bld/pytorch_1544137972173/work/aten/src/TH/generic/THTensorEvenMoreMath.cpp:191

出现这个的原因是我发现传入的inputs里存在负数,然后debug了一下以前正确的代码,我猜想这个地方传入的必须是非负数,因为建词典的时候肯定不存在indices为负数的情况。
(2019.01.26又出现了这个bug,原因是我词汇表的维度设置的太小了)


image.png

p.s.这个地方传入的inputs的维度是(batch_size,seq_len)

7.torch.nn.LSTM()
官方文档说明:


LSTM

参考:
LSTM:Pytorch实现
Pytorch的LSTM的理解
聊一聊PyTorch中LSTM的输出格式
参数:

  • input_size:x的特征维度
  • hidden_size:隐藏层的特征维度
  • num_layers:lstm隐层的层数,默认为1
  • bias:False则bih=0和bhh=0. 默认为True
  • batch_first:True则输入输出的数据格式为 (batch, seq, feature)
  • dropout:除最后一层,每一层的输出都进行dropout,默认为: 0
  • bidirectional:True则为双向lstm默认为False

输入数据格式

  • input(seq_len, batch, input_size)
    seq_len体现序列的长度,也就是这串输入中明确的单词的个数。第二个维度表示如果希望一次在网络中走完整个序列可以设置为1,第三个维度是输入的向量的维度,一般是词嵌入的维度。
  • h0(num_layers * num_directions, batch, hidden_size)
  • c0(num_layers * num_directions, batch, hidden_size)

输出数据格式

  • output(seq_len, batch, hidden_size * num_directions)
    output保存了最后一层,每个time step的输出h,如果是双向LSTM,每个time step的输出h = [h正向, h逆向] (同一个time step的正向和逆向的h连接起来)。
  • hn(num_layers * num_directions, batch, hidden_size)
    h_n保存了每一层,最后一个time step的输出h,如果是双向LSTM,单独保存前向和后向的最后一个time step的输出h。
  • cn(num_layers * num_directions, batch, hidden_size)
    output保存了最后一层每个time-step的输出,如果是双向LSTM,

我们会看到lstm(i.view(1,1,-1),hidden)这种形式,其实就是输入的数据形式应该为(seq_len, batch, input_size)这种三维的,hidden的输入也会有人写成(h0,c0),然后再去初始化他们的值在这里我们是直接在一开始就将它们初始化并进行了拼接。

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

torch.manual_seed(1)
lstm = nn.LSTM(3,3)
# 也就是seq_len是5,5个time-step
inputs = [torch.randn(1,3) for _ in range(5)]
# print(inputs)
# print(torch.randn(1,1,3))

# 也可以在类里自己定义初始化,维度是(num_layers * num_directions, batch, hidden_size)
hidden = (torch.randn(1,1,3),torch.randn(1,1,3))


# 逐个读入序列的元素
for i in inputs:
    # print(i.view(1,1,-1))
    out,hidden = lstm(i.view(1,1,-1),hidden)
    print("out\n",out)
    print("hidden\n",hidden)

#以下是直接读入整个序列,LSTM返回的第一个值表示所有时刻的隐状态值,第二个表示最近的隐状态值
# 所以下面的out_all和hidden_all是一样的
#out_all是最后一层每个time-step的输出值,这里我们只有一层LSTM。
# hidden_all的第一个张量h_n表示的是最后一个time_step的值
inputs = torch.cat(inputs).view(len(inputs),1,-1)
out_all,hidden_all = lstm(inputs,hidden)
print(out_all)
print(hidden_all)

8.产生随机数https://zhuanlan.zhihu.com/p/31231210

9.NLLLoss 的 输入 是一个对数概率向量和一个目标标签. 它不会为我们计算对数概率. 适合网络的最后一层是log_softmax. 损失函数 nn.CrossEntropyLoss() 与 NLLLoss() 相同, 唯一的不同是它为我们去做 softmax.

10.Pytorch数据读取(Dataset, DataLoader, DataLoaderIter)
参考:
Pytorch数据读取
PyTorch源码解读之torch.utils.data.DataLoader
Dataset
DataLoader
DataLoaderIter
从上往下装入 
当代码运行到要从torch.utils.data.DataLoader类生成的对象中取数据的时候,就会调用DataLoader类的iter方法,iter方法就一行代码:return DataLoaderIter(self),输入正是DataLoader类的属性。因此当调用iter方法的时候就牵扯到另外一个类:DataLoaderIter。

import torch
import torch.utils.data as Data
torch.manual_seed(1)

BATCH_SIZE = 5
x = torch.linspace(1,10,10)
y = torch.linspace(10,1,10)

torch_dataset = Data.TensorDataset(x,y)
loader = Data.DataLoader(
    dataset=torch_dataset,
    batch_size=BATCH_SIZE,
    shuffle=True
)
# 将所有的数据训练了3次
for epoch in range(3):
    #总共有10条数据,batch_size是5,每个epoch训练两次
    for step,(batch_x,batch_y) in enumerate(loader):
        print("Epoch:",epoch,"|step:",step,"|batch x:",batch_x.numpy(),"|batch y:",batch_y.numpy())
print("\n")

结果:
Epoch: 0 |step: 0 |batch x: [ 5.  7. 10.  3.  4.] |batch y: [6. 4. 1. 8. 7.]
Epoch: 0 |step: 1 |batch x: [2. 1. 8. 9. 6.] |batch y: [ 9. 10.  3.  2.  5.]
Epoch: 1 |step: 0 |batch x: [ 4.  6.  7. 10.  8.] |batch y: [7. 5. 4. 1. 3.]
Epoch: 1 |step: 1 |batch x: [5. 3. 2. 1. 9.] |batch y: [ 6.  8.  9. 10.  2.]
Epoch: 2 |step: 0 |batch x: [ 4.  2.  5.  6. 10.] |batch y: [7. 9. 6. 5. 1.]
Epoch: 2 |step: 1 |batch x: [3. 9. 1. 8. 7.] |batch y: [ 8.  2. 10.  3.  4.]

# 如果batch_size是8,不够分成两次的,那第二次返回的就是剩下的数据
# eg.
torch_dataset2 = Data.TensorDataset(x,y)
loader2 = Data.DataLoader(
    dataset=torch_dataset2,
    batch_size= 8 ,
    shuffle=True
)
for epoch in range(3):
    # 总共有10条数据,batch_size是5,so training for 2 times
    for step, (batch_x, batch_y) in enumerate(loader2):
        print("Epoch:", epoch, "|step:", step, "|batch x:", batch_x.numpy(), "|batch y:", batch_y.numpy())

结果:
Epoch: 0 |step: 0 |batch x: [ 4. 10.  9.  8.  7.  6.  1.  2.] |batch y: [ 7.  1.  2.  3.  4.  5. 10.  9.]
Epoch: 0 |step: 1 |batch x: [5. 3.] |batch y: [6. 8.]
Epoch: 1 |step: 0 |batch x: [9. 8. 4. 6. 5. 3. 7. 2.] |batch y: [2. 3. 7. 5. 6. 8. 4. 9.]
Epoch: 1 |step: 1 |batch x: [10.  1.] |batch y: [ 1. 10.]
Epoch: 2 |step: 0 |batch x: [ 5.  1.  3.  7.  6. 10.  9.  8.] |batch y: [ 6. 10.  8.  4.  5.  1.  2.  3.]
Epoch: 2 |step: 1 |batch x: [2. 4.] |batch y: [9. 7.]

11.Autograd
from torch.autograd import Variable
Tensor在被封装为Variable后,可以调用.backward实现反向椽笔,自动计算所以梯度...Variable包含三个属性:data,grad,grad_fn

y = x.detach()正如其名, 将返回一个不参与计算图的Tensor y, Tensor y 一旦试图改变修改自己的data, 会被语法检查和python解释器监测到, 并抛出错误.
requires_grad直接挂在Tensor类下,也可以将requires_grad作为一个参数, 构造tensor
https://www.itency.com/topic/show.do?id=494122

# 可学习的参数可以通过net.parameters()查看
params = list(net.parameters())

# 同时返回可学习的参数和名称
for name,parameters in net.named_parameters():
    print(name,":",parameters.size())

Variable节点和Function节点,Variable记录运算数据,Function记录运算操作。其中Variable节点又可以分为叶节点和非叶节点两类。叶节点由用户直接创建产生,而非叶节点则由Variable节点之间的运算操作产生。
如果一个节点由用户创建,则它为叶节点,对应的grad_fn是None。
grad_fn可以查看这个variable的反向传播函数,grad_fn.next_functions[0][0]

12.pack_padded_sequence VS pad_packed_sequence

torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_first=False)
输入的input需要按长度降序排列,lengths需要从大到小排序。
input的维度:T x B x * ,T表示一个最长的数据长度(the length of the longest sequence),B表示batch_size,如果batch_first=True,意味着维度是B x T x *
lengths:每个batch的数据长度(Expected len(lengths) to be equal to batch_size)

返回的数据是一个PackedSequence 对象。包含data和batch_size,其中的data是对input按列算的值,batch_size是这一列去掉padding的0之后的数量。
参考pytorch中如何处理RNN输入变长序列padding

排序的思路的话,可以先对lengths进行sort,然后再使用index_select对input进行排序。

# 降序方法1
sort_index = np.argsort(-np.array(lengths))

# 降序方法2
lengths = torch.tensor(lengths)
_, idx_sort = torch.sort(lengths, dim=0, descending=True)

可以参考pytorch里的pack_padded_sequence和pad_packed_sequence解析
pytorch学习笔记(二十一): 使用 pack_padded_sequence

我的个人方法:

import numpy as np
import torch

data = [[1,1,1,1],[2,2,2,2,2],[3,3,3,3,3,3],[4,4,4,4,4,4,4]]
# print(type(data))
data_length = [len(item) for item in data]
max_len = np.max(data_length)
new_array = np.zeros((len(data), max_len))
for index, data in enumerate(data):
    # print(index,data)
    new_array[index][:len(data)] = data
data_tensor = torch.from_numpy(new_array)
_, indices = torch.sort(torch.tensor(data_length), descending=True)
# print(indices)
print(data_tensor[indices])

_, idx_sort = torch.sort(lengths, dim=0, descending=True)
x = torch.index_select(padding_tensor,0,idx_sort)
x_packed = nn.utils.rnn.pack_padded_sequence(input=x, lengths=lengths[idx_sort],batch_first=True)



把这个PackedSequence 对象送入网络中,生成出来的还是PackedSequence 对象,这时候就需要pad_packed_sequence啦,pad_packed_sequence是pack_padded_sequence的一个逆操作。
torch.nn.utils.rnn.pad_packed_sequence(sequence, batch_first=False, padding_value=0.0, total_length=None)
T x B x * 在batch_first=True的情况下返回B x T x *
返回的是一个tuple,第一维是👆
第二维是每条数据对应的长度。

13.eval即evaluation模式,train即训练模式。仅仅当模型中有Dropout和BatchNorm时才会有影响。因为训练时dropout和BN都开启,而一般而言测试时dropout被关闭,BN中的参数也是利用训练时保留的参数,所以测试时应进入评估模式

  1. nn.Linear(in_features, out_features, bias=True)
    参数:in_features是输入sample的维度,out_features是输出sample的维度。
    输入:(N, *, in_features): where *∗ means any number of additional dimensions


    image.png

    image.png
  1. 在进行预测的时候,需要写到with torch.no_grad()里面。

16.torch.transpose(input, dim0, dim1)
返回输入矩阵input的转置,交换维度dim0和dim1。输入张量与输出张量共享内存。

image.png

17.torch.nn.functional.max_pool1d
输入维度:minibatch✖️in_channels✖️iT✖️iH✖️iW
根据torch.nn.MaxPool1d(kernel_size, stride=None, padding=0, dilation=1, return_indices=False, ceil_mode=False)
输入的维度是(N,C,Lin),输出是(N,C,Lout)。
Lout的计算公式:

image.png

18.nn.CrossEntropyLoss()
input的第一项是y_pred,第二项是y_target,今天踩的坑是把它俩位置放反了,百思不得其解报错信息。官方文档是这么说的:


image.png

顺便附上这张图或许可以更好的理解输出的维度代表的意思:


image.png

19.torch.max(input, dim, keepdim=False, out=None)
input是个tensor
dim为1,表示按行选最大的
dim为0,表示按列选最大的。
返回值是(Tensor, LongTensor),第一个是max的值,第二个是max的索引值.

怎么用?可以用来计算预测准确的数量:

#####二分类的输出#####
pred = torch.tensor([[0.1,-0.2],[0.3,0.5],[0.2,-0.1]])
label = torch.tensor([0,0,1])
#pred_label为预测的类别,label为标注的类别
pred_label = torch.max(pred,1)[1]
print(pred_label)
print(float((pred_label == label).sum())/len(label)*100)

20.2019.01.16今日踩坑:
取tensor中的数,忘记在哪里看过说如果用tensor.data获取其中的值并进行叠加的话会加到动态图中???
如果一个tensor只有一个元素,那么可以使用tensor.item()方法取出这个元素作为普通的python数字。如果tensor有多个元素,用tensor.tolist()方法可以取出。

  1. nn.Conv1d & nn.Conv2d
    nn.Conv1d:
    主要参数:input_channel(看一个博客里说这个是词嵌入的维度), output_channel, kernel_size, stride, padding.
    输入:(batch_size, num of input channels,文本长度)
    输出:(batch_size, num of output channels(我理解的是用多少个卷积核去卷积),Lout(这里是用那个卷积的公式计算出来的))
# 16表示input_channel,是词嵌入的维度,33是out_channel,是用几个卷积核进行卷积,3是表示卷积核的大小,这里是(3*词嵌入的维度)
m = nn.Conv1d(16, 33, 3, stride=2)
# input2 = torch.randn()
# 输入:N*C*L:batch_size为20,C为词嵌入的维度,50为句子的length
# 输出:N*Cout*Lout:Cout我理解的是out_channel的数量
#要注意输入的维度是词嵌入在第二维,还是句子的length在第二维,不行就用permute()或者transpose()修改维度的顺序。
input2 = torch.randn(20, 16, 50)
output2 = m(input2)
print(output2.size())

22.2019.01.25今日踩坑:
contiguous()一般与transpose,permute,view搭配使用
即使用transpose或permute进行维度变换后,调用contiguous,然后方可使用view对维度进行变形。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容