pytorch学习笔记(一)

一、Tensor的创建和计算

1.1 Tensor创建矩阵

举例说明创建矩阵,展现创建的矩阵结果

import torch
import numpy as np
#利用torch生成矩阵
>>>torch.rand(3, 2)
tensor([[0.5283, 0.8029],
        [0.0923, 0.0134],
        [0.9148, 0.3751]])
>>>torch.zeros(4, 5)
tensor([[0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.],
        [0., 0., 0., 0., 0.]])
>>>torch.ones(3, 2)
tensor([[1., 1.],
        [1., 1.],
        [1., 1.]])
#---------------------------------------------------------------------#
#利用torch对随机矩阵做全0,全1处理
>>>x = torch.rand(2, 3)
>>>torch.ones_like(x)
tensor([[1., 1., 1.],
        [1., 1., 1.]])
>>>torch.zeros_like(x)
tensor([[0., 0., 0.],
        [0., 0., 0.]])
#---------------------------------------------------------------------#
#列表与tensor之间的转换
>>>arr = [[2, 1], [3, 4]]
>>>torch.tensor(arr, dtype = torch.float32)
tensor([[2., 1.],
        [3., 4.]])
#数组与tensor之间的转换        
>>>arr_np = np.random.rand(2, 3)
>>>x = torch.from_numpy(arr_np)#这种转换方式对数组或者tensor做改变时是两者一同改变
>>>x
tensor([[0.8521, 0.7132, 0.7816],
        [0.2398, 0.7463, 0.1454]], dtype=torch.float64)
>>>arr_np
array([[0.85209142, 0.71316369, 0.78164645],
       [0.2397969 , 0.74628828, 0.14539923]])
#对数组或者tensor做改变时是两者一同改变       
>>>arr_np[0, 0] = 100
>>>x[0, 1] = -88
>>>x
tensor([[100.0000, -88.0000,   0.7816],
        [  0.2398,   0.7463,   0.1454]], dtype=torch.float64)
>>>arr_np
array([[100.        , -88.        ,   0.78164645],
       [  0.2397969 ,   0.74628828,   0.14539923]])

1.2 两个矩阵之间逐元素的运算

举例说明矩阵之间逐元素的加、减、乘、除运算,没有展示运算结果

import torch
x = torch.tensor([[2, 1], [3, 4]], dtype=torch.float32)
x = torch.tensor([[2, 1], [3, 4]], dtype=torch.float32)
#加法
ans = x + y   #method1
ans = torch.add(x, y)   #method2
x.add_(y)   #method3,x的值改变了
#减法
ans = x - y   #method1
ans = torch.sub(x, y)   #method2
x.sub_(y)   #method3,x的值改变了
#乘法
ans = x * y   #method1
ans = torch.mul(x, y)   #method2
x.mul_(y)   #method3,x的值改变了
#除法
ans = x / y   #method1
ans = torch.div(x, y)   #method2
x.div_(y)   #method3,x的值改变了

PS:带下划线的函数(add_)代表它会修改调用它的tensor

1.3 一个矩阵里元素的运算

举例说明矩阵元素的和、行和、列和、平均值、列平均、行平均、转置,展示运算结果

>>>import torch
>>>x = torch.tensor([[2, 1], [3, 4], [5, 6]], dtype=torch.float32)
#分别求x的所有元素的和、列和、行和
>>>x.sum()
tensor(21.)
>>>x.sum(dim=0)
tensor([10., 11.])
>>>x.sum(dim=1)
tensor([ 3.,  7., 11.])
#分别求x的所有元素的平均值、列平均、行平均
>>>x.mean()
tensor(3.5000)
>>>x.mean(dim=0)
tensor([3.3333, 3.6667])
>>>x.mean(dim=1)
tensor([1.5000, 3.5000, 5.5000])
#转置
>>>x.t()
tensor([[2., 3., 5.],
        [1., 4., 6.]])

1.4 索引和reshape

举例说明对tensor的索引和reshape,展示运算结果

>>>import torch
>>>x = torch.rand(3, 4)
>>>x
tensor([[0.3247, 0.5537, 0.1376, 0.4530],
        [0.8614, 0.5346, 0.1358, 0.0199],
        [0.8739, 0.1300, 0.7789, 0.0408]])
>>>x[0, 0]
tensor(0.3247)
>>>x[0, :]
tensor([0.3247, 0.5537, 0.1376, 0.4530])
>>>x[:, 1]
tensor([0.5537, 0.5346, 0.1300])
#--------------------------------------------------------------------------#
>>>a = torch.rand(10)
>>>a
tensor([0.7970, 0.3091, 0.8120, 0.1747, 0.2038, 0.3221, 0.8222, 0.9940, 0.4642,
        0.7811])
>>>a.view(2, 5)
tensor([[0.7970, 0.3091, 0.8120, 0.1747, 0.2038],
        [0.3221, 0.8222, 0.9940, 0.4642, 0.7811]])
>>>a.reshape(2, 5)
tensor([[0.7970, 0.3091, 0.8120, 0.1747, 0.2038],
        [0.3221, 0.8222, 0.9940, 0.4642, 0.7811]])
#--------------------------------------------------------------------------#
#对tensor增加一个维度、减少一个维度
>>>b = torch.rand(10)
>>>c = b.unsqueeze(0)
>>>c.shape
torch.Size([1, 10])
>>>c
tensor([[0.5024, 0.9933, 0.9953, 0.3648, 0.5116, 0.5077, 0.8112, 0.4136, 0.9798, 0.7237]])
>>>d = b.unsqueeze(1)
>>>d.shape
torch.Size([10, 1])
>>>d
tensor([[0.5024],
        [0.9933],
        [0.9953],
        [0.3648],
        [0.5116],
        [0.5077],
        [0.8112],
        [0.4136],
        [0.9798],
        [0.7237]])
>>>d.squeeze(1)
tensor([0.5024, 0.9933, 0.9953, 0.3648, 0.5116, 0.5077, 0.8112, 0.4136, 0.9798, 0.7237])

二、Auto Gradient

2.1用pytorch计算gradient

以标量与标量之间的求导为例
在这里插入图片描述

a = torch.tensor(3.0, requires_grad=True)
b = torch.tensor(4.0, requires_grad=True)
f1 = 2 * a
f2 = a * b
z = f1 + f2
# 判断a, b是否是可以求导的
print(a.requires_grad)
print(b.requires_grad)
# 求导,通过backward函数来实现
z.backward()
# 查看导数,也即所谓的梯度
print(a.grad)
print(b.grad)
"""
结果:
True
True
tensor(6.)
tensor(3.)
"""

三、Linear Regression的numpy和Autograd实现

3.1Linear Regression的numpy实现

在这里插入图片描述

import numpy as np
np.random.seed(0)

X = np.array([[1, 2], [2, 3], [4, 6], [3, 1]], dtype=np.float32)
y = np.array([[8], [13], [26], [9]], dtype=np.float32)
# y = 2*x1 + 3*x2

w = np.random.rand(2, 1)
iter_count = 20
lr = 0.02

def forward(x):
    return np.matmul(x, w)

def loss(y, y_pred):
    return ((y - y_pred) ** 2 / 2).sum()

def gradient(x, y, y_pred):
    return np.matmul(x.T, y_pred - y)

#训练
for i in range(iter_count):
    y_pred = forward(X)
    l = loss(y, y_pred)
    print('iter:', i, 'loss:', l)
    grad = gradient(X, y, y_pred)

    w = w - lr * grad

print('final parameter:', w)

#验证
X = np.array([4, 5], dtype=np.float32)
y = np.array([23], dtype=np.float32)
y_pred = forward(X)
l = loss(y, y_pred)
print('y_pred:', y_pred, 'loss:', l)

结果

iter: 0 loss: 278.14714630032296
iter: 1 loss: 77.59571864079426
iter: 2 loss: 21.675989423797887
iter: 3 loss: 6.079895897474896
iter: 4 loss: 1.7266762624675036
iter: 5 loss: 0.5086279342292306
iter: 6 loss: 0.1652608744028746
iter: 7 loss: 0.06627582981084085
iter: 8 loss: 0.03587531004022907
iter: 9 loss: 0.024985026708277826
iter: 10 loss: 0.019869268506777994
iter: 11 loss: 0.016652061185069258
iter: 12 loss: 0.014212738382501366
iter: 13 loss: 0.012204361865516435
iter: 14 loss: 0.010500494041050353
iter: 15 loss: 0.00904029592288675
iter: 16 loss: 0.007784768732834882
iter: 17 loss: 0.006704061304346578
iter: 18 loss: 0.005773506914201419
iter: 19 loss: 0.004972152763015856
final parameter: [[2.03893705]
 [2.97062014]]
y_pred: [23.0088489] loss: 3.91515526204997e-05

3.2Linear Regression的Autograd实现

依旧以3.1中的例子为例,用pytorch实现这个Linear Regression需要做出如下修改:
(1)数据X,y都要改为tensor形式
(2)pytorch中会自动计算gradient,不再需要自己定义
(3)更新参数需要改为Pytorch中的方式
如下:

import torch
torch.manual_seed(0)

X = torch.tensor([[1, 2], [2, 3], [4, 6], [3, 1]], dtype=torch.float32)
y = torch.tensor([[8], [13], [26], [9]], dtype=torch.float32)
# y = 2*x1 + 3*x2

w = torch.rand(2, 1, requires_grad=True, dtype=torch.float32)

iter_count = 20
lr = 0.02

def forward(x):
    return torch.matmul(x, w)

def loss(y, y_pred):
    return ((y - y_pred) ** 2 / 2).sum()

#训练
for i in range(iter_count):
    y_pred = forward(X)
    l = loss(y, y_pred)
    print('iter:', i, 'loss:', l)

    l.backward()
    with torch.no_grad():
        w -= lr * w.grad
        w.grad.zero_()

print('final parameter:', w)

#验证
X = torch.tensor([4, 5], dtype=torch.float32)
y = torch.tensor([23], dtype=torch.float32)
y_pred = forward(X)
l = loss(y, y_pred)
print('y_pred:', y_pred, 'loss:', l)

结果

iter: 0 loss: tensor(275.9003, grad_fn=<SumBackward0>)
iter: 1 loss: tensor(76.9414, grad_fn=<SumBackward0>)
iter: 2 loss: tensor(21.4695, grad_fn=<SumBackward0>)
iter: 3 loss: tensor(6.0016, grad_fn=<SumBackward0>)
iter: 4 loss: tensor(1.6870, grad_fn=<SumBackward0>)
iter: 5 loss: tensor(0.4822, grad_fn=<SumBackward0>)
iter: 6 loss: tensor(0.1447, grad_fn=<SumBackward0>)
iter: 7 loss: tensor(0.0491, grad_fn=<SumBackward0>)
iter: 8 loss: tensor(0.0213, grad_fn=<SumBackward0>)
iter: 9 loss: tensor(0.0125, grad_fn=<SumBackward0>)
iter: 10 loss: tensor(0.0091, grad_fn=<SumBackward0>)
iter: 11 loss: tensor(0.0074, grad_fn=<SumBackward0>)
iter: 12 loss: tensor(0.0062, grad_fn=<SumBackward0>)
iter: 13 loss: tensor(0.0053, grad_fn=<SumBackward0>)
iter: 14 loss: tensor(0.0046, grad_fn=<SumBackward0>)
iter: 15 loss: tensor(0.0039, grad_fn=<SumBackward0>)
iter: 16 loss: tensor(0.0034, grad_fn=<SumBackward0>)
iter: 17 loss: tensor(0.0029, grad_fn=<SumBackward0>)
iter: 18 loss: tensor(0.0025, grad_fn=<SumBackward0>)
iter: 19 loss: tensor(0.0022, grad_fn=<SumBackward0>)
final parameter: tensor([[2.0257],
        [2.9806]], requires_grad=True)
y_pred: tensor([23.0058], grad_fn=<SqueezeBackward3>) loss: tensor(1.6966e-05, grad_fn=<SumBackward0>)

四、Loss、Optimizer和Module

4.1交叉熵损失

pytorch中有很多自带的损失可以直接调用,不用再像3.1中自己定义损失函数。
交叉熵损失:在分类问题模型中,如逻辑回归、神经网络等,在这些模型的最后通常会经过一个sigmoid函数(softmax函数),输出一个概率值(一组概率值),这个概率值反映了预测为正类的可能性(一组概率值反应了所有分类的可能性)。而对于预测的概率分布和真实的概率分布之间,使用交叉熵来计算他们之间的差距。

(1)BCELoss
BCELoss 是CrossEntropyLoss的一个特例,只用于二分类问题
BCELoss前面需要加上Sigmoid函数

torch.nn.BCELoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean')
#weight:每个分类的缩放权重,传入的大小必须和类别数量一至
#size_average:bool类型,为True时,返回的loss为平均值,为False时,返回的各样本的loss之和
#reduce:bool类型,返回值是否为标量,默认为True
#reduction:string类型,‘none’ | ‘mean’ | 'sum’三种参数值

(2)NLLLoss
多分类的交叉熵函数,在使用前需要对input进行log_softmax处理

torch.nn.NLLLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')

(3)CrossEntropyLoss
相当于整合了log_softmax和NLLLoss()

torch.nn.CrossEntropyLoss(weight: Optional[torch.Tensor]= None, size_average=None, ignore_index: int = -100, reduce=None, reduction: str = 'mean')

4.2Optimizer

pytorch与优化函数相关的部分在torch.optim模块中,其中包含了大部分现在已有的流行的优化方法。
(1)创建optimizer 对象
要想使用optimizer,需要创建一个optimizer 对象,这个对象会保存当前状态,并根据梯度更新参数。
例如

optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum = 0.9)
optimizer = optim.Adam([var1, var2], lr = 0.0001)

(2)更新参数

optimizer.step()

多数optimizer里都可以这么做,每次用backward()这类的方法计算出了梯度后,就可以调用一次这个方法来更新参数。
(3)导数清零

optimizer.zero_grad()

4.3Module

使用pytorch自带的loss,optimizer,module来改写3.2中的例子

import torch
torch.manual_seed(0)

X = torch.tensor([[1, 2], [2, 3], [4, 6], [3, 1]], dtype=torch.float32)
y = torch.tensor([[8], [13], [26], [9]], dtype=torch.float32)
# y = 2*x1 + 3*x2

# w = torch.rand(2, 1, requires_grad=True, dtype=torch.float32)
iter_count = 100
lr = 0.001

# def forward(x):
#     return torch.matmul(x, w)
class MyModel(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.w = torch.nn.Parameter(torch.rand(2, 1, dtype=torch.float32))
        self.linear = torch.nn.Linear(2, 1)

    def forward(self, x):
        return self.linear(x)

# def loss(y, y_pred):
#     return ((y - y_pred) ** 2 / 2).sum()
criterion = torch.nn.MSELoss(reduction='sum')

model = MyModel()
optimizer = torch.optim.SGD(model.parameters(), lr)

#训练
for i in range(iter_count):
    #前向传播
    # y_pred = forward(X)
    y_pred = model(X)
    # l = loss(y, y_pred)
    l = criterion(y_pred, y)
    print('iter:', i, 'loss:', l)

    #反向传播
    l.backward()
    optimizer.step()
    optimizer.zero_grad()
    # with torch.no_grad():
    #     w -= lr * w.grad
    #     w.grad.zero_()

print('final parameter:', model.linear.weight)

#验证
X = torch.tensor([4, 5], dtype=torch.float32)
y = torch.tensor([23], dtype=torch.float32)
# y_pred = forward(X)
y_pred = model(X)
# l = loss(y, y_pred)
l = criterion(y_pred, y)
print('y_pred:', y_pred, 'loss:', l)

结果

...
iter: 95 loss: tensor(0.2015, grad_fn=<MseLossBackward>)
iter: 96 loss: tensor(0.2005, grad_fn=<MseLossBackward>)
iter: 97 loss: tensor(0.1995, grad_fn=<MseLossBackward>)
iter: 98 loss: tensor(0.1985, grad_fn=<MseLossBackward>)
iter: 99 loss: tensor(0.1976, grad_fn=<MseLossBackward>)
final parameter: Parameter containing:
tensor([[1.9147, 2.9316]], requires_grad=True)
y_pred: tensor([22.8306], grad_fn=<AddBackward0>) loss: tensor(0.0287, grad_fn=<MseLossBackward>)

五、Dataset和DataLoader

5.1介绍几个术语

Data size:要训练的数据大小
Batch(批 / 一批样本):将整个训练数据分成若干个Batch。
Batch_Size(批大小):每批样本的大小。
Iteration:训练一个Batch就是一次Iteration
Epoch:一次Epoch就是要训练的数据都喂给module一遍

5.2Dataset与DataLoader

在 PyTorch中,我们的数据集往往会用一个类去表示,在训练时用 Dataloader 产生一个 batch 的数据。
简单说,用 一个类抽象地表示数据集,而 Dataloader 作为迭代器,每次产生一个 batch 大小的数据,节省内存。
Dataset 是 PyTorch 中用来表示数据集的一个抽象类,我们的数据集可以用这个类来表示。
准备一个10*3的数据放在111.txt文件里,举例如下:

import torch
import numpy as np
from torch.utils.data import Dataset, DataLoader

class MyDataset(Dataset):
    def __init__(self):
        """载入数据"""
        txt_data = np.loadtxt('111.txt', delimiter=',')
        self._x = torch.from_numpy(txt_data[:, :2])
        self._y = torch.from_numpy(txt_data[:, 2])
        self._len = len(txt_data)

    def __getitem__(self, item):
        """返回相应位置的数据"""
        return self._x[item], self._y[item]

    def __len__(self):
        """返回整个数据长度"""
        return self._len

data = MyDataset()
dataloader = DataLoader(data, batch_size=3, shuffle=True, drop_last=True, num_workers=0)
n = 0
for data_val, label_val in dataloader:
    print('x:', data_val, 'y:', label_val)
    n +=1
print('iteraton', n)

结果

x: tensor([[16., 17.],
        [10., 11.],
        [13., 14.]], dtype=torch.float64) y: tensor([18., 12., 15.], dtype=torch.float64)
x: tensor([[ 4.,  5.],
        [ 1.,  2.],
        [22., 23.]], dtype=torch.float64) y: tensor([ 6.,  3., 24.], dtype=torch.float64)
x: tensor([[ 7.,  8.],
        [19., 20.],
        [28., 29.]], dtype=torch.float64) y: tensor([ 9., 21., 30.], dtype=torch.float64)
iteraton 3

不定期更新,如有问题,欢迎指教!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值