数据操作

主要学习了简单的 pytorch 张量创建、参数以及运算操作。

# 导入pytorch包
import torch

# 初始化一个有12个元素的行张量 
x = torch.arange(12)

# 查看形状
x.shape
x.numel()

# 改变形状为 3 x 4
x = x.reshape(3, 4)

# 生产一个 2 x 3 x 4 的全0张量
torch.zeros((2, 3, 4))

# 生产一个 2 x 3 x 4 的全1张量
torch.ones((2, 3, 4))

# 张量的加、减、乘、除和幂运算
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x**y
torch.exp(x)

# 不同维度进行拼接
X = torch.arange(12, dtype=torch.float32).reshape((3, 4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)

# 判断相等
X == Y

# 元素求和
X.sum()

# 广播机制,会自动对齐长度
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a + b

# 查看某个元素
X[-1], X[1: 3]

# 改变单个元素
X[1, 2] = 9

# 改变多个元素
X[0:2, :] = 12

# 相加会新建元素,改变内存位置
before = id(Y)
Y = Y + X
id(Y) == before

# 采用逐元素赋值或者+=不会改变内存位置
Z = torch.zeros_like(Y)
print('id(Z):', id(Z))
Z[:] = X + Y
print('id(Z):', id(Z))

before = id(X)
X += Y
id(X) == before

# numpy 与 tensor 转换
A = X.numpy()
B = torch.tensor(A)
type(A), type(B)

# 单个张量转换为 float 或 int
a = torch.tensor([3.5])
a, a.item(), float(a), int(a)

数据预处理

本节主要是通过例子讲解了简单的数据预处理操作。

# 在上一级目录下生产一个data目录,并存入一个 house_tiny.csv 文件
import os
os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house_tiny.csv')

# 在 house_tiny.csv 文件中写入内容
with open(data_file, 'w') as f:
    f.write('NumRooms, Alley, Price\n')
    f.write('NA, Pave, 127500\n')
    f.write('2, NA, 106000\n')
    f.write('4, NA, 178100\n')
    f.write('NA, NA, 140000\n')

# 使用 pandas 读取文件数据
import pandas as pd
data = pd.read_csv(data_file)
print(data)

# 按列读取数据分为输入和输出
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean())
print(inputs)

# 处理为 one-hot 编码
inputs = pd.get_dummies(inputs, dummy_na = False)
print(inputs)

# 将数据转化为 tensor
import torch
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y

线性代数

本节主要讲解了简单的线性代数知识和代码实现

# 导入 pytorch 包
import torch

# 生成标量,并进行运算
x = torch.tensor([3.0])
y = torch.tensor([2.0])
x+y, x*y, x/y, x**y

# 查看长度、形状
x = torch.arange(4)
len(x)
x.shape

# 转置运算
A = torch.arange(20).reshape(5, 4)
A.T
B = torch.tensor([[1,2,3],[2,0,4],[3,4,5]])
B == B.T

# 克隆操作,并进行元素相加
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone()
A, A+B

# 逐元素相乘
A*B

# 标量与张量相加和相乘
a = 2
X = torch.arange(24).reshape(2, 3, 4)
a + X, (a * X).shape

# 张量求和
x = torch.arange(4, dtype=torch.float32)
x, x.sum()

# 按照第二个维度求和, 会使该维度消失
A.shape, A.sum(dim=1)

# 按照第二个维度求和, 并保持总维度不变,求和维度变成1
sum_A = A.sum(axis=1, keepdims=True)
sum_A

# 计算平均值
A / sum_A

# 累加求和
A.cumsum(axis=0)

# 点积
y = torch.ones(4, dtype=torch.float32)
x, y, torch.dot(x, y)
torch.sum(x*y)

# 矩阵与向量相乘
A, x, A.shape, x.shape, torch.mv(A, x)

# 矩阵与矩阵相乘
B = torch.ones(4, 3)
torch.mm(A, B)

# L2范数
u = torch.tensor([3.0, -4.0])
torch.norm(u)

# L1范数
torch.abs(u).sum()

# F范数
torch.norm(torch.ones((4, 9)))

# 按特定轴求和
a = torch.ones((2,5,4))
a.shape
a.sum(axis=[0,2]).shape
a.sum(axis=[0, 2], keepdims=True).shape

矩阵计算

本节主要讲了如何对向量、矩阵进行求导的相关内容

第一周学习_数据预处理

第一周学习_数据预处理_02

第一周学习_线性代数_03

第一周学习_线性代数_04

自动求导

本节主要讲了如何使用 pytorch 进行自动求导

import torch

# 生成张量并保存梯度
x = torch.arange(4.0)
x.requires_grad_(True)
x.grad

# 通过 backward 函数求梯度
y = 2 * torch.dot(x, x)
y.backward()
x.grad

# 梯度不会自动清零,需要手动
# pytorch 一般只进行标量对向量求梯度
x.grad.zero_()
y = x.sum()
y.backward()
x.grad

x.grad.zero_()
y = x*x
y.sum().backward()
x.grad

x.grad.zero_()
y = x*x
u = y.detach()
z = u * x
z.sum().backward()
x.grad == u

x.grad.zero_()
y.sum().backward()
x.grad == 2*x


# 自定义函数进行求梯度
def f(a):
    b = a * 2
    while b.norm() < 1000:
        b = b * 2
    if b.sum() > 0:
        c = b
    else:
        c = 100 * b
    return c

a = torch.randn(size=(), requires_grad=True)
d = f(a)
d.backward()

a.grad == d / a

pytorch 通过前向传播和反向传播进行自动求导,求导过程只能对叶子节点进行,可以通过在创建张量时指定 requires_grad 参数为 True 来设置为叶子节点,也可以后续通过 requires_grad_() 函数修改,单叶子节点后不能再存在叶子节点,否则修改会失败。在求导过程中,可以通过 retain_grad() 函数保存非叶子节点的梯度。