pytorch 深度学习笔记(一)

一、线性回归

1.pytorch 的Broadcasting Semantics
如果遵守以下规则,则两个张量是“可播放的”:

每个张量至少有一个维度。
迭代尺寸大小时,从尾随尺寸开始,尺寸大小必须相等,其中一个为1,或者其中一个不存在。
例如:

x=torch.empty(5,7,3)
y=torch.empty(5,7,3)
same shapes are always broadcastable (i.e. the above rules always hold)

x=torch.empty((0,))
y=torch.empty(2,2)
x and y are not broadcastable, because x does not have at least 1 dimension
can line up trailing dimensions

x=torch.empty(5,3,4,1)
y=torch.empty( 3,1,1)
x and y are broadcastable.
1st trailing dimension: both have size 1
2nd trailing dimension: y has size 1
3rd trailing dimension: x size == y size
4th trailing dimension: y dimension doesn’t exist

but:

x=torch.empty(5,2,4,1)
y=torch.empty( 3,1,1)
x and y are not broadcastable, because in the 3rd trailing dimension 2 != 3

如果两个张量x,y是“broadcastable”,所得到的张量大小的计算方法如下:
如果尺寸的数量x和y不相等,则在尺寸较小的张量的前面加1,使它们的长度相等。
然后,对于每个维度大小,生成的维度大小是该维度的大小x和y沿该维度的最大值 。
例如:

can line up trailing dimensions to make reading easier

x=torch.empty(5,1,4,1)
y=torch.empty( 3,1,1)
(x+y).size()
torch.Size([5, 3, 4, 1])

but not necessary:

x=torch.empty(1)
y=torch.empty(3,1,7)
(x+y).size()
torch.Size([3, 1, 7])

x=torch.empty(5,2,4,1)
y=torch.empty(3,1,1)
(x+y).size()
RuntimeError: The size of tensor a (2) must match the size of tensor b (3) at non-singleton dimension 1
就地语义
一个复杂因素是就地操作不允许就地张量由于广播而改变形状。

例如:

x=torch.empty(5,3,4,1)
y=torch.empty(3,1,1)
(x.add_(y)).size()
torch.Size([5, 3, 4, 1])

but:

x=torch.empty(1,3,1)
y=torch.empty(3,1,7)
(x.add_(y)).size()
RuntimeError: The expanded size of the tensor (1) must match the existing size (7) at non-singleton dimension 2.

向后兼容性

PyTorch的早期版本允许某些逐点函数在具有不同形状的张量上执行,只要每个张量中的元素数量相等即可。然后通过将每个张量视为1维来执行逐点运算。PyTorch现在支持广播,并且“1维”逐点行为被认为已弃用,并且在张量不可播放但具有相同数量的元素的情况下将生成Python警告。

注意,在两个张量不具有相同形状但是可广播并且具有相同数量的元素的情况下,广播的引入可能导致向后不兼容的改变。例如:

torch.add(torch.ones(4,1), torch.randn(4))
之前会产生一个尺寸为Tensor的尺寸:torch.Size([4,1],
但现在产生尺寸为Tensor:torch.Size([4,4])。
为了帮助识别代码中可能存在广播引起的向后不兼容性的情况,
您可以将torch.utils.backcompat.broadcast_warning.enabled设置为True,这将在这种情况下生成python警告。

例题

损失函数定义为:

def squared_loss(y_hat, y):
return (y_hat - y.view(y_hat.size())) **
2 / 2 将返回结果替换为下面的哪一个会导致会导致模型无法训练:

(y_hat.view(-1) - y) ** 2 / 2

(y_hat - y.view(-1)) ** 2 / 2

(y_hat - y.view(y_hat.shape)) ** 2 / 2

(y_hat - y.view(-1, 1)) ** 2 / 2

答案解释:
y_hat的形状是[n, 1],而y的形状是[n],两者相减得到的结果的形状是[n, n],相当于用y_hat的每一个元素分别减去y的所有元素,所以无法得到正确的损失值。对于第一个选项,y_hat.view(-1)的形状是[n],与y一致,可以相减;对于第二个选项,y.view(-1)的形状仍是[n],所以没有解决问题;对于第三个选项和第四个选项,y.view(y_hat.shape)和y.view(-1, 1)的形状都是[n, 1],与y_hat一致,可以相减。以下是一段示例代码:

x = torch.arange(3)
y = torch.arange(3).view(3, 1)
print(x)
print(y)
print(x + y)

二、Softmax与分类模型

y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y = torch.LongTensor([0, 2])
y_hat.gather(1, y.view(-1, 1))
output:
tensor([[0.1000],
[0.5000]])

#gether前面的1的意思是选择第一行的第一个词,第二行的第三个词,表示对行操作

torch.gather(input, dim, index, out=None) → Tensor

返回的tensor的size与index的size一致。

dim用于指明index的元素值代表的维数。这个函数可以用来很方便地提取方阵

2.softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类!

存在问题
当我们运算比较小的值的时候是不会有什么问题的,但是如果运算的值比较大的时候,比如xn很大或很小的时候,朴素的直接计算会上溢出或下溢出,从而导致严重问题。
举个例子,对于[3,1,-3],直接计算是可行的,我们可以得到(0.88,0.12,0)。

但对于[1000,1000,1000],却并不可行,我们会得到inf(这也是深度学习训练过程常见的一个错误,看了本文之后,以后出现inf的时候,至少可以考虑softmax运算的上溢和下溢);对于[-1000,-999,-1000],还是不行,我们会得到-inf。

这是因为你的浮点数只有64位,在计算指数函数的环节,exp{1000} =inf,会发生上溢出;exp{-1000} =0,会发生下溢出。
解决办法
解决办法很简单:
对任意a都成立,这意味着我们可以自由地调节指数函数的指数部分,一个典型的做法是取 xn中的最大值:a=max{x1,x2…xn}
这可以保证指数最大不会超过0,于是你就不会上溢出。即便剩余的部分下溢出了,加了a之后,你也能得到一个合理的值。

三、文本预处理

文本是一类序列数据,一篇文章可以看作是字符或单词的序列,本节将介绍文本数据的常见预处理步骤,预处理通常包括四个步骤:

  1. 读入文本
  2. 分词
  3. 建立字典,将每个词映射到一个唯一的索引(index)
  4. 将文本从词的序列转换为索引的序列,方便输入模型

1 .读入文本
用到的函数:

re.sub(pattern, repl, string, count=0, flags=0)

pattern:表示正则表达式中的模式字符串;
repl:被替换的字符串(既可以是字符串,也可以是函数);
string:要被处理的,要被替换的字符串;
count:匹配的次数, 默认是全部替换
flags:具体用处不详

line.strip() #去掉前缀的、后缀的空白字符,包括空格和换行符(只能删除开头或者结尾的字符,不能删除中间部分的字符)

代码分析:

import collections
import re

def read_time_machine():
    with open('/home/kesci/input/timemachine7163/timemachine.txt', 'r') as f:
        lines = [re.sub('[^a-z]+', ' ', line.strip().lower()) for line in f]
    return lines


lines = read_time_machine()
print('# sentences %d' % len(lines))

其中每次读取f中的一行文件,然后把这行文件中的前缀、后缀的空格和换行符删除,并全部转化为小写字母。再将每行中不是[a-z]字母的字符串替换成空格,即把非英文字符的字符串全部替换成空格,得到lines列表。

2.分词
对每个句子进行分词,也就是将一个句子划分成若干个词(token),转换为一个词的序列。

代码分析:

def tokenize(sentences, token='word'):
    """Split sentences into word or char tokens"""
    if token == 'word':
        return [sentence.split(' ') for sentence in sentences] # 用空格做分隔符进行分隔
    elif token == 'char':
        return [list(sentence) for sentence in sentences]  # 将句子直接转换成列表
    else:
        print('ERROR: unkown token type '+token)

tokens = tokenize(lines)
tokens[0:2]

传入参数:

sentences表示传入的句子,token表示做哪个级别的分词,是’word’还是’char’。

3 建立字典
为了方便模型处理,我们需要将字符串转换为数字。因此我们需要先构建一个字典(vocabulary),将每个词映射到一个唯一的索引编号。

代码分析:

class Vocab(object):
    def __init__(self, tokens, min_freq=0, use_special_tokens=False):
        counter = count_corpus(tokens
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值