python 深度学习,基于pytorch 的学习笔记,,
numpy 复习
- 使用np.random 生成随机数组
- np.random.choice()
import numpy as np
from numpy import random as nr
a=np.arange(1,25,dtype=float)
c1=nr.choice(a,size=(3,4)) #size指定输出数组形状
c2=nr.choice(a,size=(3,4),replace=False) #replace缺省为True,即可重复抽取。
#下式中参数p指定每个元素对应的抽取概率,不设置就是每个元素被抽取的概率相同。
c3=nr.choice(a,size=(3,4),p=a / np.sum(a))
- 构建数组
- np.savetxt( X=data, fname=’./test1.txt’) 保持数据到文本
- data = np.loadtxt(’./test.txt’)
- 改变数组形状
arr =np.arange(6).reshape(2, -1)
print(arr)
print("按照列优先,展平")
print(arr.ravel('F'))
print("按照行优先,展平")
print(arr.ravel())
输出结果:
[[0 1 2]
[3 4 5]]
按照列优先,展平
[0 3 1 4 2 5]
按照行优先,展平
[0 1 2 3 4 5]
# flatten 将矩阵转为向量,通常在卷积网络与全连接层之间
a =np.floor(10*np.random.random((3,4)))
print(a.flatten())
[[4. 0. 8. 5.]
[1. 0. 4. 8.]
[8. 2. 3. 7.]]
[4. 0. 8. 5. 1. 0. 4. 8. 8. 2. 3. 7.]
# squeeze降维的
arr =np.arange(3).reshape(3, 1)
print(arr.shape) #(3,1)
print(arr.squeeze().shape) #(3,)
arr1 =np.arange(6).reshape(3,1,2,1)
print(arr1.shape) #(3, 1, 2, 1)
print(arr1.squeeze().shape) #(3, 2)
# transpose 轴转换,深度学习中可以用来吧图片从 RGB -> GBR
arr2 = np.arange(24).reshape(2,3,4)
print(arr2.shape) #(2, 3, 4)
print(arr2.transpose(1,2,0).shape) #(3, 4, 2)
- 数组合并
- append concatenate stack 都有一个 axis 参数,控制数组的合并方式是按行还是按列
- 合并是注意两者的形状要匹配。
a =np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
c = np.concatenate((a, b), axis=0) # 跨行
print(c)
d = np.concatenate((a, b.T), axis=1)
print(d)
[[1 2]
[3 4]
[5 6]]
[[1 2 5]
[3 4 6]]
a =np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print(np.stack((a, b), axis=0)) # 这个是按指定轴堆叠数组或矩阵
[[[1 2]
[3 4]]
[[5 6]
[7 8]]] # 维数是不一样的
- 批量处理
随机梯度下降法嘛,,SGD。分批次处理
#生成10000个形状为2X3的矩阵
data_train = np.random.randn(10000,2,3)
#这是一个3维矩阵,第一个维度为样本数,后两个是数据形状
print(data_train.shape)
#(10000,2,3)
#打乱这10000条数据
np.random.shuffle(data_train)
#定义批量大小
batch_size=100
#进行批处理
for i in range(0,len(data_train),batch_size):
x_batch_sum=np.sum(data_train[i:i+batch_size]) # 批处理数据集
print("第{}批次,该批次的数据之和:{}".format(i,x_batch_sum))
-
通用函数
-
广播机制
Tensor
与numpy 相似,可以是零维,多维数组,并共享内存,区别就是Tensor 可以放到GPU 中加速计算。
针对 Tensor 的操作,按照接口划分:
- torch.function,比如 torch.sum torch.add(x,y) ( 等价于 x.add(y))
- tensor.function 比如 tensor.view,tensor.add
针对修改方式:
- 不修改自身数据:x.add(y) x不变,返回一个新的Tensor
- 修改自身数据:x.add_(y) 修改x
x=torch.tensor([1,2])
y=torch.tensor([3,4])
z=x.add(y)
print(z)
print(x)
x.add_(y)
print(x)
tensor([4, 6])
tensor([1, 2])
tensor([4, 6])
- 创建:
函数 | 功能 |
---|---|
Tensor(*size) | 从参数中构造一个张量,支持List, Numpy数组 |
eye(row,column) | 创建指定行数,列数的二维单位Tensor |
linspace(start, end, stepes) | 等差数列 |
logspace(start,end,steps) | 从 10^start 到 10^end ,分成steps份 |
rand/randn(*size) | 生成 [0,1) 均匀分布/标准正态分布数据 |
ones/zeros/ones_likes/zeros_like/arange(start,end,step) | 都懂。。 |
from_Numpy(ndarray) | 从ndarray 创建一个Tensor |
torch.Tensor([1,2,3,4,5,6])
torch.Tensor(2,3)
t=torch.Tensor([[1,2,3],[4,5,6]])
t.size(),t.shape # shape 与 size 等价
>>> (torch.Size([2, 3]), torch.Size([2, 3]))
torch.Tensor(t.size()) # 根据已有形状创建
>>>
tensor([[0., 0., 0.],
[0., 0., 0.]])
# torch.Tensor and torch.tensor 的区别
t1 = torch.Tensor(1)
t2= torch.tensor(1)
print(t1,t1.type(),t2,t2.type()) # Tensor使用默认的dtype(FloatTensor) .tensor从数据中推断类型
>>> tensor([7.3447e-16]) torch.FloatTensor tensor(1) torch.LongTensor
# tensor(1)返回一个固定值1,而Tensor() 返回的是大小为 1 的随机张量
- 修改形状
函数 | 说明 |
---|---|
size() | 返回张量的 shape 值与函数,shape 等价 |
numel(input) | 计算Tensor 的元素个数 |
view(*shape) | 修改Tensor 的shape,与 Reshape类似,返回的对象与原Tensor 共享内存,修改一个都会修改。Reshape 就是生成一个新对象,而且不要求 原Tensor是连续的,View(-1) 展平数组 |
resize | 类似于view,但在 size 超出时重新分配内存。 |
item | 若Tensor是单元素,返回python 的标量 |
unsqueeze | 在指定维度加个1 |
squeeze | 在指定维度压缩一个1 |
x = torch.randn(2, 3)
x.size()
>>> torch.Size([2, 3])
#查看x的维度
x.dim() #结果为2
#把x变为3x2的矩阵
x.view(3,2)
#把x展平为1维向量
y=x.view(-1)
y.shape >>> torch.Size([6])
#添加一个维度
z=torch.unsqueeze(y,0)
#查看z的形状
z.size() #结果为torch.Size([1, 6])
#计算Z的元素个数
z.numel() #结果为6
torch.view and torch.reshape 的区别:
- reshape()可以由,torch.reshape() or torch.Tensor.reshape() 调用。但 view() 只能由 torch.Tensor.view() 调用。
- 对一个要被view 的 Tensor,新的size 必须与原来的 size与 stride 兼容,否则在之前调用contiguous 方法()
- 只想重塑张量,使用torch.reshape ,如果还关注内存的使用并确保两个张量共享相同的数据,使用torch.view。
- 索引操作
索引操作与numpy类似,一般来说 索引结果与源数据共享内存。索引还可以通过一些函数
函数 | 说明 |
---|---|
index_select(input, dim, index) | 在指定维度上选择一些行或列 |
nonzero(input) | 获取非 0 元素的下标 |
masked_select(input, mask) | 使用二元值进行选择 |
gather( input, dim ,index) | 在指定维度上选择数据,输出的形状与 Index(LongTensor类型) 一致。 |
scatter_(input, dim, index, src) | gather 的反操作,根据指定索引补充数据 |
torch.manual_seed(100) # 一个随机种子
x = torch.randn(2,3)
x
>>>
tensor([[ 0.3607, -0.2859, -0.3938],
[ 0.2429, -1.3833, -2.3134]])
x[1,1:] # >>> tensor([-1.3833, -2.3134])
x[:,-1] # >>> tensor([-0.3938, -2.3134])
mask=x>0 # 生成是否大于零的 Byter 张量
# tensor([[ True, False, False], mask
# [ True, False, False]])
torch.masked_select(x,mask) # >>> tensor([0.3607, 0.2429]) 大于零的值
torch.nonzero(mask)
# tensor([[0, 0], # 非零下标,就是行,列的索引。
# [1, 0]])
torch.index_select(x,1,torch.tensor([0,2])) # 指定维度的跨行索引。。
>>>
tensor([[ 0.3607, -0.3938],
[ 0.2429, -2.3134]])
#获取指定索引对应的值,输出根据以下规则得到
#out[i][j] = input[index[i][j]][j] # if dim == 0 对行的操作
#out[i][j] = input[i][index[i][j]] # if dim == 1 对列的操作,,啥玩意。。
index=torch.LongTensor([[0,1,1],[1,1,1]])
a=torch.gather(x,1,index)
a
>>>
tensor([[ 0.3607, -0.2859, -0.2859],
[-1.3833, -1.3833, -1.3833]])
#把a的值返回到一个2x3的0矩阵中
z=torch.zeros(2,3)
torch.scatter(z,1,index,a) # 顶层没有scratter_() 方法
z.scatter_(1,index,a)
>>>
tensor([[ 0.3607, -0.2859, 0.0000], # 对指定索引补充数据,,这又是啥。。
[ 0.0000, -1.3833, 0.0000]])
torch.gather 脑补连接
语言处理中,给每个单词上一个标签,现在我们有四个句子(由单词标签构成的不同长度的句子):
input = [
[2, 3, 4, 5],
[1, 4, 3],
[4, 2, 2, 5, 7],
[1]
]
进行填充,padding
input = [
[2, 3, 4, 5, 0, 0],
[1, 4, 3, 0, 0, 0],
[4, 2, 2, 5, 7, 0],
[1, 0, 0, 0, 0, 0]
]
现在要从填充后的input 中选出最后一个单词的标签。
input = [
[2, 3, 4, 5, 0, 0],
[1, 4, 3, 0, 0, 0],
[4, 2, 2, 5, 7, 0],
[1, 0, 0, 0, 0, 0]
]
input = torch.tensor(input) # 在指定维度上选择数据,输出的形状与 Index(LongTensor类型) 一致。
#注意index的类型 ,
# 将input的第i维的大小更改为y,且要满足y>=1(除了第i维之外的其他维度,大小要和input保持一致)
length = torch.LongTensor([[3],[2],[4],[0]]) # 学废了吗
out = torch.gather(input, 1, length)
out
tensor([[5],
[3],
[7],
[1]])
length = torch.LongTensor([[3,0],[2,0],[4,0],[0,0]])
out = torch.gather(input, 1, length)
out
tensor([[5, 2],
[3, 1],
[7, 4],
[1, 1]])
length = torch.LongTensor([[2,3]]) # 前两行的第三个,第四个元素
out = torch.gather(input, 0, length)
out
tensor([[4, 0]])
torch.scatter 脑部链接
就是把input数组中的数据进行重新分配。index中表示了要把原数组中的数据分配到output数组中的位置,如果未指定,则填充0。就是index 中的是index 中元素在 output 中的位置。
不一定所有的input数据都会分到output中,output也不是所有位置都有对应的input,当output中没有对应的input时,自动填充0。
一般scatter用于生成onehot向量,
index = torch.tensor([[1], [2], [0], [3]])
onehot = torch.zeros(4, 4)
onehot.scatter_(1, index, 1)
print(onehot)
tensor([[0., 1., 0., 0.],
[0., 0., 1., 0.],
[1., 0., 0., 0.],
[0., 0., 0., 1.]])
- 广播机制
A = np.arange(0, 40,10).reshape(4, 1)
B = np.arange(0, 3)
#把ndarray转换为Tensor
A1=torch.from_numpy(A) #形状为4x1
B1=torch.from_numpy(B) #形状为3
print(A1.shape,B1.size())
#Tensor自动实现广播
C=A1+B1 # torch.Size([4, 1]) torch.Size([3]) -> 4,3
print(C)
#我们可以根据广播机制,手工进行配置
#根据规则1,B1需要向A1看齐,把B变为(1,3)
B2=B1.unsqueeze(0) #B2的形状为1x3
#使用expand函数重复数组,分别的4x3的矩阵
A2=A1.expand(4,3)
B3=B2.expand(4,3)
#然后进行相加,C1与C结果一致
C1=A2+B3
print(C1)
>>>
torch.Size([4, 1]) torch.Size([3])
tensor([[ 0, 1, 2],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]], dtype=torch.int32)
tensor([[ 0, 1, 2],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]], dtype=torch.int32)
- 逐元素操作
大多逐元素操作与numpy 类似,如果需要就地操作,可以在后面加个下划线 add_()
函数 | 说明 |
---|---|
abs/add | 绝对值,加法 |
addcdiv( t,v,t1, t2) | t1 ,t2 按元素除后,乘 v 加 t 。 |
addcmul( t, v, t1, t2) | t1,t2 按元素乘后,乘v 加 t |
ceil /floor | 向上取整,向下取整 |
clamp(t, min, max) | 将张量元素限制在指定区间 |
exp/log/pow | 指数,对数,幂 |
mul or * /neg | 逐元素乘法/ 取反 |
sigmoid/tanh/softmax | 激活函数,,专业 |
sign/sqrt | 取符号,开根 |
感受到了np 之处。。
t = torch.randn(1, 3)
t1 = torch.randn(3, 1)
t2 = torch.randn(1, 3)
#t+0.1*(t1/t2)
torch.addcdiv(t, 0.1, t1, t2)
#计算sigmoid
torch.sigmoid(t)
#将t限制在[0,1]之间
torch.clamp(t,0,1)
#t+2进行就地运算
t.add_(2)
- 归并操作
对输入进行归并或合计等操作。。归并操作可以针对整个 Tensor or 针对某一个 axis
函数 | 说明 |
---|---|
cumprod(t, axis) | 累积 |
cumsum | 累加 |
dist(a,b,p=2) | 返回a,b 之间的 p 阶范数(二阶就是距离吧) |
mean/median | 均值/中位数 |
std/var | 标准差/方差 |
norm(t,p=2) | t 的 p 阶范数 |
prod(t)/sum(t) | t 中所用元素的积/和 |
归并操作一般有一个 dim 参数,指定在那个维度进行归并,keepdim 决定是否要保留维度1.默认不保留
a=torch.linspace(0,10,6)
a=a.view((2,3))
#沿y轴方向累加,即dim=0
b=a.sum(dim=0) #b的形状为[3] ,等于 a.sum(axis=0) 对列操作
>>> tensor([ 6., 10., 14.])
#沿y轴方向累加,即dim=0,并保留含1的维度
b=a.sum(dim=0,keepdim=True) #b的形状为[1,3]
>>>tensor([[ 6., 10., 14.]])
- 比较操作
一般是逐元素比较,有些是按指定方向比较
函数 | 说明 |
---|---|
eq | 比较Tensor 是否相等 |
equal | 比较两个Tensor s是否有相同的shape与值 |
ge/le/gt/lt | 大于/小于 / 大于等于/小于等于 |
max/min(t,axis) | 最值,指定axis 额外返回下标 |
topk(t,k,axis) | 指定axis 维上取最高的K 个值 |
x=torch.linspace(0,10,6).view(2,3)
#求所有元素的最大值
torch.max(x) #结果为10
#求y轴方向的最大值
torch.max(x,dim=0) #结果为[6,8,10]
>>>
torch.return_types.max(
values=tensor([ 6., 8., 10.]), # 专业
indices=tensor([1, 1, 1]))
#求最大的2个元素
torch.topk(x,2,dim=0)
>>>
torch.return_types.topk(
values=tensor([[ 6., 8., 10.],
[ 0., 2., 4.]]),
indices=tensor([[1, 1, 1],
[0, 0, 0]]))
- 矩阵操作
函数 | 说明 |
---|---|
dot(t1,t2) | 内积或点积 |
mm(mat1,mat2)/bmm(batch1,batch2) | 计算矩阵乘法/含batch 的3D 矩阵乘法 |
mv(t1,t2) | 计算矩阵与向量乘法 |
svd(t) | 计算t 的SVD 分解 |
t | 转置 |
- Torch的 dot 是对两个 一维的点积运算,mm 才是2D 的矩阵的点积运算,bmm 3D点积。numpy中的dot 没有限制
a=torch.tensor([2, 3])
b=torch.tensor([3, 4])
torch.dot(a,b)
tensor(18)
x=torch.randint(10,(2,3))
y=torch.randint(6,(3,4))
torch.mm(x,y)
tensor([[36, 77, 81, 41],
[45, 63, 69, 42]])
x=torch.randint(10,(2,2,3))
y=torch.randint(6,(2,3,4))
torch.bmm(x,y)
(tensor([[[1, 8, 9],
[0, 0, 6]],
[[2, 4, 8],
[0, 4, 3]]]),
tensor([[[0, 2, 2, 0],
[0, 1, 1, 5],
[1, 5, 5, 0]],
[[4, 2, 0, 1],
[4, 5, 3, 3],
[4, 0, 5, 1]]]))
tensor([[[ 9, 55, 55, 40],
[ 6, 30, 30, 0]], # 就是两个二维矩阵的点乘。。然后stack 堆叠起来
[[56, 24, 52, 22],
[28, 20, 27, 15]]])