Pytorch学习Day02[连载]

一、张量的操作

1、cat 张量拼接

t=torch.ones((2,3))
t_0=torch.cat([t,t],dim=0) #2+2
t_1=torch.cat([t,t],dim=1) #3+3
print('t_0:{} shape:{}\n t_1:{} shape:{}'.format(t_0,t_0.shape,t_1,t_1.shape))

结果:

t_0:tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]]) shape:torch.Size([4, 3])
 t_1:tensor([[1., 1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1., 1.]]) shape:torch.Size([2, 6])

2、stack 创建新维度,扩展维度

t=torch.ones((2,3))
t_stack=torch.stack([t,t],dim=0) #在第0维度再创建一个维度并进行拼接
print('\nt:{} shape:{}'.format(t,t.shape))
print('\nt_stack:{} shape:{}'.format(t_stack,t_stack.shape))

结果:(是在第一维度位置拼接)

t:tensor([[1., 1., 1.],
        [1., 1., 1.]]) shape:torch.Size([2, 3])
t_stack:tensor([[[1., 1., 1.],
         [1., 1., 1.]],
        [[1., 1., 1.],
         [1., 1., 1.]]]) shape:torch.Size([2, 2, 3])

如果在第3维度插入,会改变比较大的形状

t=torch.ones((2,3))
t_stack=torch.stack([t,t],dim=0) #在第0维度再创建一个维度并进行拼接
print('\nt:{} shape:{}'.format(t,t.shape))
print('\nt_stack:{} shape:{}'.format(t_stack,t_stack.shape))

结果:(是在第一维度位置拼接)

t:tensor([[1., 1., 1.],
        [1., 1., 1.]]) shape:torch.Size([2, 3])
t_stack:tensor([[[1., 1.],
         [1., 1.],
         [1., 1.]],
        [[1., 1.],
         [1., 1.],
         [1., 1.]]]) shape:torch.Size([2, 3, 2])

3、chunk 将张量按维度dim进行平均切分

a=torch.ones((2,7))
list_of_tensors=torch.chunk(a,dim=1,chunks=3)
#切分两份张量

for idx,t in enumerate(list_of_tensors):
    print('第{}个张量:{}, shape is {}'.format(idx+1,t,t.shape))

结果:7/3=2.5,所以 分的话是3, 3,1

第1个张量:tensor([[1., 1., 1.],
        [1., 1., 1.]]), shape is torch.Size([2, 3])
第2个张量:tensor([[1., 1., 1.],
        [1., 1., 1.]]), shape is torch.Size([2, 3])
第3个张量:tensor([[1.],
        [1.]]), shape is torch.Size([2, 1])

4、split 将张量按维度dim进行切分

t=torch.ones((2,5))
list_of_tensors=torch.split(t,2,dim=1)
list_of_tensors=torch.split(t,[2,1,2],dim=1) #按照list上数值来切分,注意list各元素之和=dim维上元素之和
for idx,t in enumerate(list_of_tensors):
    print('第{}个张量:{}. shape is {}'.format(idx+1,t,t.shape))

结果:

第1个张量:tensor([[1., 1.],
        [1., 1.]]). shape is torch.Size([2, 2])
第2个张量:tensor([[1.],
        [1.]]). shape is torch.Size([2, 1])
第3个张量:tensor([[1., 1.],
        [1., 1.]]). shape is torch.Size([2, 2])

5、index_select() 按index索引数据

t=torch.ones((2,5))
list_of_tensors=torch.split(t,2,dim=1)
list_of_tensors=torch.split(t,[2,1,2],dim=1) #按照list上数值来切分,注意list各元素之和=dim维上元素之和
for idx,t in enumerate(list_of_tensors):
    print('第{}个张量:{}. shape is {}'.format(idx+1,t,t.shape))

结果:

t:
tensor([[5, 6, 2],
        [7, 1, 7],
        [1, 4, 8]])
t_select:
tensor([[5, 6, 2],
        [1, 4, 8]])

6、masked_select() 筛选数据,按照mask中的True进行索引

t=torch.randint(0,9,size=(3,3))
mask=t.ge(5) #ge大于等于 greater than or equal  gt大于 le小于等于
t_select=torch.masked_select(t,mask)
print('t:\n{}\nmask:{}\nt_select:\n{}'.format(t,mask,t_select))

结果:

t:
tensor([[0, 3, 0],
        [1, 7, 5],
        [3, 5, 5]])
mask:tensor([[False, False, False],
        [False,  True,  True],
        [False,  True,  True]])
t_select:
tensor([7, 5, 5, 5])

7、reshape 变换张量形状

t=torch.randperm(8)
# t_reshape=torch.reshape(t,(2,4))
# t_reshape=torch.reshape(t,(-1,4)) #采用8/4来得到新维度
t_reshape=torch.reshape(t,(-1,2,2)) #采用8/2/2来得到新维度,新维度也就是赋值为-1的维度
print('t:{}\nt_reshape:\n{}'.format(t,t_reshape.shape))

结果:

t:tensor([1, 2, 5, 4, 0, 3, 7, 6])
t_reshape:
torch.Size([2, 2, 2])

此处也体现出内存共享

t[0]=1024
print('t:{}\nt_reshape:\n{}'.format(t,t_reshape))
print('t.data 内存地址:{}'.format(id(t.data)))
print('t_reshape.data 内存地址:{}'.format(id(t_reshape.data)))

结果:

t:tensor([1024,    2,    5,    4,    0,    3,    7,    6])
t_reshape:
tensor([[[1024,    2],
         [   5,    4]],
        [[   0,    3],
         [   7,    6]]])
t.data 内存地址:1691486721592
t_reshape.data 内存地址:1691486721592

8、torch.transpose() 交换维度

t=torch.rand((2,3,4))
t_transpose=torch.transpose(t,dim0=0,dim1=2) #c*h*w--->h*w*c
print('t shape:{}\n t_transpose shape:{}'.format(t.shape,t_transpose.shape))

结果:

t shape:torch.Size([2, 3, 4])
t_transpose shape:torch.Size([4, 3, 2])

9、二维张量转置torch.rand,对矩阵而言,等价torch.transpose(input,0,1)

t=torch.rand((2,3))
t_t=torch.t(t)
print('t shape:{}\n t_t shape:{}'.format(t.shape,t_t.shape))

结果:

t shape:torch.Size([2, 3])
 t_t shape:torch.Size([3, 2])

10、张量变换 squeeze 压缩长度为1的维度

dim 若为None,移除所有长度为1的轴;若指定维度,当且仅当该轴长度为1时,可以移除。

t=torch.rand((1,2,3,1))
t_sq=torch.squeeze(t) #长度为1的轴被移除
t_0=torch.squeeze(t,dim=0) #指定
t_1=torch.squeeze(t,dim=1) #虽然指定,但是由于长度不为1,所以也不会被压缩
print(t.shape)
print(t_sq.shape)
print(t_0.shape)
print(t_1.shape)

结果:

torch.Size([1, 2, 3, 1])
torch.Size([2, 3])
torch.Size([2, 3, 1])
torch.Size([1, 2, 3, 1])

11、unsqueeze() 依据dim扩展维度

dim 若为None,移除所有长度为1的轴;若指定维度,当且仅当该轴长度为1时,可以移除。

t=torch.rand((1,2,3,1))
t_2=torch.unsqueeze(t,dim=1)
print('t的shape',t.shape)
print('t_2的shape',t_2.shape)

结果:

t的shape torch.Size([1, 2, 3, 1])
t_2的shape torch.Size([1, 1, 2, 3, 1])

二、张量的数学运算

1、torch.add()

这里有个trick,torch.add(a,10,b)===>a+10*b

t_0=torch.randn((3,3))
t_1=torch.ones_like(t_0)
t_add=torch.add(t_0,10,t_1)
print('t_0:\n{}\nt_1:\n{}\nt_add_10:\n{}'.format(t_0,t_1,t_add))

结果:

t_0:
tensor([[-0.0172, -0.5480,  0.9224],
        [-0.1373,  1.4477, -0.9650],
        [-0.5231,  0.3081, -1.0270]])
t_1:
tensor([[1., 1., 1.],
        [1., 1., 1.],
        [1., 1., 1.]])
t_add_10:
tensor([[ 9.9828,  9.4520, 10.9224],
        [ 9.8627, 11.4477,  9.0350],
        [ 9.4769, 10.3081,  8.9730]])

三、求导篇

1、计算图concept

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、计算图之动态图与静态图

在这里插入图片描述
在这里插入图片描述

3、autograd

autograd.backward
自动求取梯度
tensors:求导的张量
retain_Graph 保存计算图
create_graph 创建导数计算图
grad_tensors多梯度权重

(1)retain_Graph

import torch
w=torch.tensor([1.],requires_grad=True)
x=torch.tensor([2.],requires_grad=True)

a=torch.add(w,x)
b=torch.add(w,1)
y=torch.mul(a,b)

y.backward()
print(w.grad)

结果:

tensor([5.])

如果需要求某个非叶子节点的导数,需要retain_Graph=True

y.backward(retain_graph=True)
y.backward()
print(w.grad)

结果

tensor([10.])

(2)grad_tensors

w=torch.tensor([1.],requires_grad=True)
x=torch.tensor([2.],requires_grad=True)

a=torch.add(w,x)
b=torch.add(w,1)

y0=torch.mul(a,b) #y0=(x+w)*(w+1) dy0/dw=5
y1=torch.add(a,b) #y1=(x+w)+(w+1)  dy1/dw=2

loss=torch.cat([y0,y1],dim=0) #[y0.y1]
grad_tensors=torch.tensor([1.,2.])
loss.backward(gradient=grad_tensors) 
print(w.grad) 

gradient 传入 torch.autograd.backward()的grad_tensors,用于多个梯度之间权重的设置
y0导数grad_tensors[0] +y1导数grad_tensors[1]
结果:

tensor([9.])

(3)create_graph

x=torch.tensor([3.],requires_grad=True)
y=torch.pow(x,2)  #y=x**2

grad_1=torch.autograd.grad(y,x,create_graph=True) 
print(grad_1)

grad_1=dy/dx=2x=2*3=6 一阶导数,需要在create_graph,创建导数计算图,从而得出高阶求导
结果:

(tensor([6.], grad_fn=<MulBackward0>),)

再次求导

grad_2=torch.autograd.grad(grad_1[0],x) #grad_2=d(dy/dx)/dx=d(2x)/dx=2
print(grad_2)

结果:

(tensor([2.]),)

(4)梯度不会自动清零

w=torch.tensor([1.],requires_grad=True)
x=torch.tensor([2.],requires_grad=True)

for i in range(2):
    a=torch.add(w,x)
    b=torch.add(w,1)
    y=torch.mul(a,b)

    y.backward()
    print(w.grad)

结果:

tensor([5.])
tensor([10.])

所以在求完梯度后,要清零

w.grad.zero_()

这里的zero_的下划线表示in-place原地操作。

(5)依赖于叶子节点的结点,require_grad默认为True

w=torch.tensor([1.],requires_grad=True)
x=torch.tensor([2.],requires_grad=True)

a=torch.add(w,x)
b=torch.add(w,1)
y=torch.mul(a,b)

print(a.requires_grad,b.requires_grad,y.requires_grad)

结果:

True True True

(6)叶子节点不可执行in-place操作,原地操作:在原始内存中改变这个数据

w=torch.tensor([1.],requires_grad=True)
x=torch.tensor([2.],requires_grad=True)

a=torch.add(w,x)
b=torch.add(w,1)
y=torch.mul(a,b)

w.add_(1)

结果:

RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.

原理解释:
这是原始空间数据:

a=torch.ones((1,))
print(id(a),a)

结果:

1691445516952 tensor([1.])

如果不进行原地操作:

a=a+torch.ones((1,)) #开辟新空间
print(id(a),a)
a=a+torch.ones((1,)) #开辟新空间
print(id(a),a)

结果:

1691486723752 tensor([1.])
1691486722232 tensor([2.])

如果进行原地操作:

a=torch.ones((1,))
print(id(a),a)
a+=torch.ones((1,)) #原地址直接改变
print(id(a),a)

结果:

1691486723832 tensor([1.])
1691486723832 tensor([2.])

叶子节点不能原地操作,因为如果原地操作后,该数据已经改变了,那样会破坏前向传播与反向传播的数据错误,从而导致梯度求解错误

四、应用篇

在这里插入图片描述

1、线性回归

y=wx+b
确定模型
选择损失函数MSE
求梯度更新w,b

w=w-LRw.grad b=b-LRw.grad
LR是学习率

Step1: 导包+设置随机数种子

这个随机数种子作用是以种子为随机数的基本,使得首次随机生成的数,在后面运行程序时则固定下来,即首次随机生成A、b、c,那么后面再次运行的时候,还是随机生成这些数

import torch
import matplotlib.pyplot as plt
torch.manual_seed(10)
lr=0.1 #学习率

Step2: 建立模型

x=torch.rand(20,1)*10 #x data(tensor), shape=(20,1)
y=2*x+(5+torch.randn(20,1)) #y data(tensor), shape=(20,1)

(5+torch.randn(20,1)) 此处相当于给方程偏置加入噪声

Step3: 初始化线性回归参数

w=torch.randn((1),requires_grad=True) 
b=torch.zeros((1),requires_grad=True)

Step4: 开始训练

for iteration in range(1000):
    #前向传播
    wx=torch.mul(w,x)
    y_pred=torch.add(wx,b) #这里的alpha=1,所以直接就是wx+b

    #计算MSE loss
    loss=(0.5*(y-y_pred)**2).mean()

    #反向传播
    loss.backward()#计算各个参数的梯度运算

    #更新参数
    b.data.sub_(lr*b.grad)
    w.data.sub_(lr*w.grad)

Step5: 可视化

    if loss.data.numpy()<0.5:
        plt.scatter(x.data.numpy(), y.data.numpy())
        plt.plot(x.data.numpy(), y_pred.data.numpy(), 'r-', lw=5)
        plt.text(2, 20, 'Loss:%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
        plt.xlim(1.5, 10)
        plt.ylim(8, 28)
        plt.title('Iteration:{} \nw:{} b:{}'.format(iteration, w.data.numpy(), b.data.numpy()))
        plt.savefig('result.jpg')
        break

结果如图:
在这里插入图片描述

2、逻辑回归

import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
torch.manual_seed(10)

#导包

Step1: 生成数据

sample_nums=100
mean_value=1.7 
bias=1
n_data=torch.ones(sample_nums,2)
x0=torch.normal(mean_value*n_data,1)+bias  #类0 数据 shape=100,2
y0=torch.zeros(sample_nums)  #类0 标签 shape=100,1
x1=torch.normal(-mean_value*n_data,1)+bias  #类1  数据 shape=100,2
y1=torch.ones(sample_nums)  #类1 标签shape=100,1
#拼接
train_x=torch.cat((x0,x1),0)
train_y=torch.cat((y0,y1),0)

mean_value是超参,控制自变量生成

Step2: 选择模型

class LR(nn.Module):
    def __init__(self):
        super(LR, self).__init__()
        self.features=nn.Linear(2,1)
        self.sigmoid=nn.Sigmoid()

    def forward(self,x):
        x=self.features(x)
        x=self.sigmoid(x)
        return x

这里的Linear(2,1)是输入x0,x1,输出1个概率值进行分类
.并将其实例化

lr_net=LR() 

Step3: 选择损失函数

loss_fn=nn.BCELoss()

Step4: 选择优化器

lr=0.01 #学习率
optimizer=torch.optim.SGD(lr_net.parameters(),lr=lr,momentum=0.9)

Step5: 模型训练

for iteration in range(1000):
    #前行传播
    y_pred=lr_net(train_x)

    #计算loss
    loss=loss_fn(y_pred.squeeze(),train_y)

    #反向传播
    loss.backward()

    #更新参数
    optimizer.step()

Step6: 可视化(这里是接着上面循环体内)

计算参数(ge是大于等于)

	mask = y_pred.ge(0.5).float().squeeze()  # 0.5为阈值进行分类
    correct = (mask == train_y).sum()  # 计算正确预测的样本个数
    acc = correct.item() / train_y.size(0)  # 计算分类准确率

设置阈值停止训练

    if acc > 0.99:
        # 绘制训练数据
        plt.scatter(x0.data.numpy()[:, 0], x0.data.numpy()[:, 1], c='r', label='class 0')
        plt.scatter(x1.data.numpy()[:, 0], x1.data.numpy()[:, 1], c='b', label='class 1')

        # 绘制逻辑回归模型
        w0, w1 = lr_net.features.weight[0]
        w0, w1 = float(w0.item()), float(w1.item())
        plot_b = float(lr_net.features.bias[0].item())
        plot_x = np.arange(-6, 6, 0.1)
        plot_y = (-w0 * plot_x - plot_b) / w1

        plt.xlim(-5, 7)
        plt.ylim(-7, 7)
        plt.plot(plot_x, plot_y)
        plt.text(-5, 5, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'})
       
        plt.title(
            'Iteration: {}\nw0:{:.2f} w1:{:.2f} b: {:.2f} accuracy:{:.2%}'.format(iteration, w0, w1, plot_b, acc))
        plt.legend()

        plt.show()
        plt.pause(0.5)
        break

结果为:
在这里插入图片描述
终于总结完了。没想到就因为偷懒了一下,积压了两次课的内容,搞了一晚上才搬迁完成,知识量激增。加油加油。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值