人工智能入门(一) Torch基本使用

本文目录

环境安装

PyTorch官网
Jupyter NoteBook

PyTorch数据类型操作

import torch

x = torch.arange(12)  # 使用arange创建一个行向量x tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
x.shape  # 通过张量的 shape 属性来访问张量的形状 torch.Size([12])
x.numel()  # 张量中元素的总数 12
X = x.reshape(3, 4)  # 要改变张量的形状
tensor([[ 0,  1,  2,  3],
          [ 4,  5,  6,  7],
          [ 8,  9, 10, 11]])
# reshape支持自动计算出一个维度用法 x.reshape(-1,4)或x.reshape(3,-1)等价于x.reshape(3,4)。

torch.zeros((2, 3, 4))  # 创建全0张量
tensor([[[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]],

        [[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]]])

torch.ones((2, 3, 4))  # 创建全1张量
tensor([[[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]],

        [[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]]])

torch.randn(3, 4)  # 创建随机张量
tensor([[ 1.0962,  0.7937, -1.8389, -0.1989],
        [ 1.5041,  0.2080,  1.4398,  1.8232],
        [-1.3178, -0.8359,  1.8015,  0.4061]])

torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])  # 手动初始化张量

# 张量计算
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  # **运算符是求幂运算
(tensor([ 3.,  4.,  6., 10.]),
 tensor([-1.,  0.,  2.,  6.]),
 tensor([ 2.,  4.,  8., 16.]),
 tensor([0.5000, 1.0000, 2.0000, 4.0000]),
 tensor([ 1.,  4., 16., 64.]))

torch.exp(x)  # 张量求幂
tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])

# 对张量分别按行和按列进行连结(concatenate)
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)
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [ 2.,  1.,  4.,  3.],
         [ 1.,  2.,  3.,  4.],
         [ 4.,  3.,  2.,  1.]]),
 tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
         [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
         [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]]))

# 对于每个位置,如果 X 和 Y 在该位置相等,则新张量中相应项的值为1,这意味着逻辑语句 X == Y 在该位置处为真,否则该位置为 0。
X == Y
tensor([[False,  True, False,  True],
        [False, False, False, False],
        [False, False, False, False]])

# 对张量中的所有元素进行求和会产生一个只有一个元素的张量。
X.sum()
tensor(66.)

# 在大多数情况下,我们将沿着数组中长度为1的轴进行广播
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b

# 由于 a 和 b 分别是 3×1 和 1×2 矩阵,如果我们让它们相加,它们的形状不匹配。
# 我们将两个矩阵广播为一个更大的 3×2 矩阵,如下所示:矩阵 a将复制列,矩阵 b将复制行,然后再按元素相加。
a + b
tensor([[0, 1],
        [1, 2],
        [2, 3]])

# 索引和切片
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
tensor([[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  6.,  7.],
        [ 8.,  9., 10., 11.]])
X[-1], X[1:3]
(tensor([ 8.,  9., 10., 11.]),
 tensor([[ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.]]))
# 写值
X[1, 2] = 9
tensor([[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  9.,  7.],
        [ 8.,  9., 10., 11.]])

# 多元素写值
X[0:2, :] = 12
tensor([[12., 12., 12., 12.],
        [12., 12., 12., 12.],
        [ 8.,  9., 10., 11.]])

# 节省内存写法一
Z = torch.zeros_like(Y)
print('id(Z):', id(Z))  # id(Z): 139674315734208
Z[:] = X + Y
print('id(Z):', id(Z))  # id(Z): 139674315734208

# 节省内存写法二
X[:] = X + Y
X += Y

# tensor与ndarray数据转换
tensor_cpu = torch.ones((2,2))  # 创建CPU类型的张量
tensor_gpu = tensor_cpu.cuda()  # CPU转GPU
tensor_cpu = tensor_gpu.cpu()   # GPU转CPU
np_array= tensor_cpu.numpy()    # tensor转ndarray
torch.from_numpy(np.ones((2,2)))  # ndarray转tensor(保留精度,ndarray默认64位精度,tensor默认32位。若通过from_numpy的方式,则会保留原来64位精度)
torch.Tensor(np.ones((2,2)))      # ndarray转tensor方式二(丢失精度,64位浮点数截断为32位)
torch.ones((1,1)).item()        # tensor cpu转scalar

pandas读写数据集

import os

# 写入数据集
os.makedirs(os.path.abspath('data'), exist_ok=True)
data_file = os.path.join(os.path.abspath('data'), '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')

# 读取数据集
import pandas as pd

data = pd.read_csv(data_file)
print(data)  # type(data) = pandas.core.frame.DataFrame
#  NumRooms Alley   Price
0       NaN  Pave  127500
1       2.0   NaN  106000
2       4.0   NaN  178100
3       NaN   NaN  140000

# 读取第0行数据
data.loc[0]
NumRooms       NaN
Alley         Pave
Price       127500
Name: 0, dtype: object

# 读取第0行的Price字段
data.loc[0]["Price"]
127500

# 处理缺失值
inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean(numeric_only=True))
print(inputs)
   NumRooms Alley
0       3.0  Pave
1       2.0   NaN
2       4.0   NaN
3       3.0   NaN

# 将NaN转换为0/1表示
# 对于inputs中的类别值或离散值,我们将“NaN”视为一个类别。由于“巷子”(“Alley”)列只接受两种类型的类别值“Pave”和“NaN”,pandas可以自动将此列转换为两列“Alley_Pave”和“Alley_nan”。巷子类型为“Pave”的行会将“Alley_Pave”的值设置为1,“Alley_nan”的值设置为0。缺少巷子类型的行会将“Alley_Pave”和“Alley_nan”分别设置为0和1。
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)
   NumRooms  Alley_Pave  Alley_nan
0       3.0           1          0
1       2.0           0          1
2       4.0           0          1
3       3.0           0          1

# 转换为张量格式
X, y = torch.tensor(inputs.values), torch.tensor(outputs.values)
X, y
(tensor([[3., 1., 0.],
         [2., 0., 1.],
         [4., 0., 1.],
         [3., 0., 1.]], dtype=torch.float64),
 tensor([127500, 106000, 178100, 140000]))


# 导入库
import numpy as np
import pandas as pd

# 导入CSV或者xlsx文件:
df = pd.DataFrame(pd.read_csv('name.csv',header=1))
df = pd.DataFrame(pd.read_excel('name.xlsx'))

# 用pandas创建数据表:
df = pd.DataFrame({"id":[1001,1002,1003,1004,1005,1006], 
"date":pd.date_range('20130102', periods=6),
"city":['Beijing ', 'SH', ' guangzhou ', 'Shenzhen', 'shanghai', 'BEIJING '],
"age":[23,44,54,32,34,32],
"category":['100-A','100-B','110-A','110-C','210-A','130-F'],
"price":[1200,np.nan,2133,5433,np.nan,4432]},
columns =['id','date','city','category','age','price'])

# 查看维度
df.shape
(6, 6)

# 数据表基本信息(维度、列名称、数据格式、所占空间等)
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6 entries, 0 to 5
Data columns (total 6 columns):
 #   Column    Non-Null Count  Dtype         
---  ------    --------------  -----         
 0   id        6 non-null      int64         
 1   date      6 non-null      datetime64[ns]
 2   city      6 non-null      object        
 3   category  6 non-null      object        
 4   age       6 non-null      int64         
 5   price     4 non-null      float64       
dtypes: datetime64[ns](1), float64(1), int64(2), object(2)
memory usage: 416.0+ bytes

# 每一列数据的格式
df.dtypes
id                   int64
date        datetime64[ns]
city                object
category            object
age                  int64
price              float64
dtype: object

# 某一列格式
df['B'].dtype

# 空值
type(df.isnull())
df.isnull()
pandas.core.frame.DataFrame
id	date	city	category	age	price
0	False	False	False	False	False	False
1	False	False	False	False	False	True
2	False	False	False	False	False	False
3	False	False	False	False	False	False
4	False	False	False	False	False	True
5	False	False	False	False	False	False

矩阵操作

# 创建矩阵
A = torch.arange(20).reshape(5, 4)
A
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11],
        [12, 13, 14, 15],
        [16, 17, 18, 19]])

# 矩阵转置
A.T
tensor([[ 0,  4,  8, 12, 16],
        [ 1,  5,  9, 13, 17],
        [ 2,  6, 10, 14, 18],
        [ 3,  7, 11, 15, 19]])

# 矩阵运算
A = torch.arange(20, dtype=torch.float32).reshape(5, 4)
B = A.clone()  # 通过分配新内存,将A的一个副本分配给B
A, A + B, A * B
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [12., 13., 14., 15.],
         [16., 17., 18., 19.]]),
 tensor([[ 0.,  2.,  4.,  6.],
         [ 8., 10., 12., 14.],
         [16., 18., 20., 22.],
         [24., 26., 28., 30.],
         [32., 34., 36., 38.]]),
 tensor([[  0.,   1.,   4.,   9.],
         [ 16.,  25.,  36.,  49.],
         [ 64.,  81., 100., 121.],
         [144., 169., 196., 225.],
         [256., 289., 324., 361.]]))

# 降维运算
x = torch.arange(4, dtype=torch.float32)
x, x.sum()
(tensor([0., 1., 2., 3.]), tensor(6.))

A.shape, A.sum()
(torch.Size([5, 4]), tensor(190.))

A
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [12., 13., 14., 15.],
         [16., 17., 18., 19.]]),
A_sum_axis0 = A.sum(axis=0)
A_sum_axis0, A_sum_axis0.shape
(tensor([40., 45., 50., 55.]), torch.Size([4]))

# 降维运算是一类操作的统称,例如求平均也是降维运算
A.sum(axis=[0, 1])
A.mean(), A.sum() / A.numel()
(tensor(9.5000), tensor(9.5000))
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
(tensor([ 8.,  9., 10., 11.]), tensor([ 8.,  9., 10., 11.]))

# 非降维求和,使用广播机制保留维度
sum_A = A.sum(axis=1, keepdims=True)
sum_A
tensor([[ 6.],
        [22.],
        [38.],
        [54.],
        [70.]])

A / sum_A
tensor([[0.0000, 0.1667, 0.3333, 0.5000],
        [0.1818, 0.2273, 0.2727, 0.3182],
        [0.2105, 0.2368, 0.2632, 0.2895],
        [0.2222, 0.2407, 0.2593, 0.2778],
        [0.2286, 0.2429, 0.2571, 0.2714]])

# 点积
y = torch.ones(4, dtype = torch.float32)
x, y, torch.dot(x, y)
(tensor([0., 1., 2., 3.]), tensor([1., 1., 1., 1.]), tensor(6.))
torch.sum(x * y)
tensor(6.)

# 矩阵-向量积
A.shape, x.shape, torch.mv(A, x)
(torch.Size([5, 4]), torch.Size([4]), tensor([ 14.,  38.,  62.,  86., 110.]))

# 矩阵-矩阵乘法
B = torch.ones(4, 3)
torch.mm(A, B)
tensor([[ 6.,  6.,  6.],
        [22., 22., 22.],
        [38., 38., 38.],
        [54., 54., 54.],
        [70., 70., 70.]])

# 范数
# 一个向量的范数告诉我们一个向量有多大。 这里考虑的大小(size)概念不涉及维度,而是分量的大小。
# 计算L2范数
u = torch.tensor([3.0, -4.0])
torch.norm(u)
tensor(5.)
# 计算L1范数
torch.abs(u).sum()
tensor(7.)

自动求导

# 对函数y=2x⊤x求导

# 创建输入值,包含四个元素的一维向量
x = torch.arange(4.0)
x
tensor([0., 1., 2., 3.])

# 共享内存,减少内存损耗
x.requires_grad_(True)  # 等价于 `x = torch.arange(4.0, requires_grad=True)`
x.requires_grad  # 默认值是False

# 计算y
# x是一个长度为4的向量,计算x和x的内积,得到了我们赋值给y的标量输出。
y = 2 * torch.dot(x, x)
y
tensor(28., grad_fn=<MulBackward0>)

# 可以通过调用反向传播函数来自动计算y关于x每个分量的梯度,并打印这些梯度。
y.backward()
x.grad
tensor([ 0.,  4.,  8., 12.])

# 函数y=2x⊤x关于x的梯度应为4x。让我们快速验证我们想要的梯度是否正确计算。
x.grad == 4 * x
tensor([True, True, True, True])

# 在默认情况下,PyTorch会累积梯度,我们需要清除之前的值
x.grad.zero_()
y = x.sum()
y.backward()
x.grad

# 非标量变量的反向传播
# 对非标量调用`backward`需要传入一个`gradient`参数,该参数指定微分函数关于`self`的梯度。
# 在我们的例子中,我们只想求偏导数的和,所以传递一个1的梯度是合适的
x.grad.zero_()
y = x * x
y.sum().backward()  # 等价于y.backward(torch.ones(len(x)))
                    # 也可以y.backward(torch.ones_like(x))
x.grad

# 分离计算
# 将计算移动到记录的计算图之外
# 在这里,我们可以分离y来返回一个新变量u,该变量与y具有相同的值,但丢弃计算图中如何计算y的任何信息。换句话说,梯度不会向后流经u到x。因此,下面的反向传播函数计算z=u*x关于x的偏导数,同时将u作为常数处理,而不是z=x*x*x关于x的偏导数。
x.grad.zero_()
y = x * x
u = y.detach()  # !Important
z = u * x
z.sum().backward()
x.grad == u
tensor([True, True, True, True])

# Python控制流的梯度计算
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)  # 创建一维随机向量,维度为0,即只有一个数据
d = f(a)
d.backward()

概率论

# 导入库
%matplotlib inline
import torch
from torch.distributions import multinomial
from d2l import torch as d2l

# 对丢色子进行抽样,众所周知每个面的概率是均分1/6
fair_probs = torch.ones([6]) / 6

# Multinomial函数第一参数为重复次数,第二参数为概率向量
multinomial.Multinomial(1, fair_probs).sample()
posted @ 2021-10-17 20:52  DXCyber409  阅读(381)  评论(0编辑  收藏  举报