LearnAI

Chapter 1 引言

是时候系统学习一下人工智能了,希望什么时候可以补充一下引言吧

  • 设备环境:Linux-Ubuntu20.04
  • 编译环境:miniconda

Chapter 2 预备知识

2.1 数据处理

2.1.1 创建张量

1
import torch

此处为torch,虽然包叫pytorch

1
2
x = torch.arange(12)
x
tensor([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

张量:数组,但里面的内容都是数值,维度不限

1
x.shape
torch.Size([12])

通过shape可以查询张量的形状;[]代表维度为1,12代表这一维度的长度

1
x.numel()
12

numel()可以访问张量中元素的总数

1
2
x = x.reshape(3, 4)
x
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])

通过reshape(c,r),可以将张量重新排列成多维形式

1
2
y = x.reshape(4, 4)
y
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

Cell In[6], line 1
----> 1 y = x.reshape(4, 4)
      2 y


RuntimeError: shape '[4, 4]' is invalid for input of size 12

但重组时,col与row的乘积必须等于元素总数

1
2
3
z = torch.zeros((2, 3, 4))
o = torch.ones((3, 2, 4))
print(z, '\n' ,o)
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.]]]) 
 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.]]])

使用zeros()构造全0矩阵,同理ones(), 没有除了1和0之外的数

1
2
x = torch.tensor([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
x
tensor([[ 1,  2,  3,  4],
        [ 5,  6,  7,  8],
        [ 9, 10, 11, 12]])

使用tensor()手动构造变量

1
torch.randn(3, 4)
tensor([[-0.2559,  0.4066,  0.4201, -1.1634],
        [-2.0670,  0.6678,  0.9912,  0.2923],
        [ 0.2710,  1.9265, -1.6423, -0.9642]])

生成随机数张量,元素平均数为0,标准差为1的正态分布中随机采样

2.1.2 张量运算

基本运算
1
2
3
x = torch.tensor([1.0,2, 4, 8])
y = torch.tensor([2, 3, 4, 5])
x+y,x-y,x*y,x/y,x**y,x%y
(tensor([ 3.,  5.,  8., 13.]),
 tensor([-1., -1.,  0.,  3.]),
 tensor([ 2.,  6., 16., 40.]),
 tensor([0.5000, 0.6667, 1.0000, 1.6000]),
 tensor([1.0000e+00, 8.0000e+00, 2.5600e+02, 3.2768e+04]),
 tensor([1., 2., 0., 3.]))

对于相同形状的张量,可以通过(+,-,*,/,%)作运算,具体来说:$I+J \rightarrow I_i+J_i$

1
2
3
import numpy
x = torch.tensor([numpy.e,numpy.log(2),1,torch.e])
torch.exp(x)
tensor([15.1543,  2.0000,  2.7183, 15.1543], dtype=torch.float64)

exp()求解e的x次方:$y_i=e^{x_i}$

张量拼接
1
2
3
x = torch.arange(12).reshape((3,4))
y = torch.tensor([[2,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]]))

通过cat()可以实现拼接,dim=0按照行,dim=1按列

1
2
3
x = torch.arange(12).reshape((3,4))
y = torch.tensor([[2,1,4],[1,2,3],[4,3,2]])
torch.cat((x,y),dim=0), torch.cat((x,y),dim=1)
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

Cell In[13], line 3
      1 x = torch.arange(12).reshape((3,4))
      2 y = torch.tensor([[2,1,4],[1,2,3],[4,3,2]])
----> 3 torch.cat((x,y),dim=0), torch.cat((x,y),dim=1)


RuntimeError: Sizes of tensors must match except in dimension 0. Expected size 4 but got size 3 for tensor number 1 in the list.

若尺寸不对应则会报错

1
2
3
x = torch.arange(12).reshape((3,4))
y = torch.tensor([[2,1,4,3],[1,2,3,4],[4,3,2,1]])
x == y
tensor([[False,  True, False,  True],
        [False, False, False, False],
        [False, False, False, False]])

近似于求位与运算

元素求和
1
2
x = torch.arange(12).reshape((3,4))
torch.sum(x), x.sum()
(tensor(66), tensor(66))
广播机制
1
2
3
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a + b
tensor([[0, 1],
        [1, 2],
        [2, 3]])

试试多维,有点废脑子

1
2
3
x = torch.tensor([ [ [1],[1],[1] ] ,[[2],[3],[4] ] ])
y = torch.tensor([ [ [1,2,3]] ])
x,y,x+y
(tensor([[[1],
          [1],
          [1]],

         [[2],
          [3],
          [4]]]),
 tensor([[[1, 2, 3]]]),
 tensor([[[2, 3, 4],
          [2, 3, 4],
          [2, 3, 4]],

         [[3, 4, 5],
          [4, 5, 6],
          [5, 6, 7]]]))
张量切片

按行切片

1
2
x = torch.arange(12).reshape((3,4))
x,x[-1],x[2],x[0:2],x[0:3],x[0:-1],x[:-1],x[:],x[:0]
(tensor([[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]]),
 tensor([ 8,  9, 10, 11]),
 tensor([ 8,  9, 10, 11]),
 tensor([[0, 1, 2, 3],
         [4, 5, 6, 7]]),
 tensor([[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]]),
 tensor([[0, 1, 2, 3],
         [4, 5, 6, 7]]),
 tensor([[0, 1, 2, 3],
         [4, 5, 6, 7]]),
 tensor([[ 0,  1,  2,  3],
         [ 4,  5,  6,  7],
         [ 8,  9, 10, 11]]),
 tensor([], size=(0, 4), dtype=torch.int64))

自定义切片

1
2
x = torch.arange(12).reshape((3,4))
x[:,1] , x[1:3,1:] , x[0::2,1::2], x[0::2,0::2]
(tensor([1, 5, 9]),
 tensor([[ 5,  6,  7],
         [ 9, 10, 11]]),
 tensor([[ 1,  3],
         [ 9, 11]]),
 tensor([[ 0,  2],
         [ 8, 10]]))

a:b:c,在区间[a,b)中取数,step=c,a,c默认为0,b默认最后一位

暴力写入
1
2
x[1, 2] = 9
x
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  9,  7],
        [ 8,  9, 10, 11]])
内存节省
1
2
3
4
y = torch.arange(4)
before = id(y)
y = y + x
id(y) == before
False

在处理变量中,一般操作会导致新建内存,如果矩阵数据特别大,容易消耗内存,可以使用原地存储

1
2
3
4
y = torch.arange(4)
before = id(y)
y += x
id(y) == before
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

Cell In[22], line 3
      1 y = torch.arange(4)
      2 before = id(y)
----> 3 y += x
      4 id(y) == before


RuntimeError: output with shape [4] doesn't match the broadcast shape [3, 4]
类型互换
1
2
3
4
5
6
y = torch.arange(4)
x = torch.arange(4,8,1)
z = torch.zeros_like(y)
print('id(z):',id(z))
z[:] = x + y
print('id(z):',id(z))
id(z): 140157950377472
id(z): 140157950377472

Pytorch与Numpy的互换

1
2
3
A = x.numpy()
B = torch.tensor(A)
type(A),type(B)
(numpy.ndarray, torch.Tensor)

将大小为1的张量转化为python标量

1
2
a = torch.tensor([3.5])
a,a.item(),float(a),int(a)
(tensor([3.5000]), 3.5, 3.5, 3)

2.2数据预处理

2.2.1 生成数据集文件

1
2
3
4
5
6
7
8
9
import os
os.makedirs(os.path.join('..','data'), exist_ok=True)
data_file = os.path.join('..', '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')

创建CSV文件:房价数据-房间数量/巷子类型/价格

1
2
3
4
import pandas as pd

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

运用pandas库读取csv

2.2.2 补充丢失数据

补充丢失数据的典型方法是插值法和删除法

  • 插值法:用一个数字替代缺失位
  • 删除法:直接忽略缺少的数据
1
2
3
inputs, outputs = data.iloc[:,0:2], data.iloc[:, 2]
inputs = inputs.fillna(inputs.mean())
print(inputs)
   NumRooms Alley
0       3.0  Pave
1       2.0   NaN
2       4.0   NaN
3       3.0   NaN

在补充房间数,使用插值法,通过插入已知数的平均值补充未知数,input.mean()读取数据平均数

1
2
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

在补充巷子时,看成是有Pave为1,无为0的矩阵形式

2.2.3 转化为张量形式

1
2
3
4
5
6
import torch

x = torch.tensor(inputs.values)
y = 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]))

利用tensor()构造张量

实例:删除空数据最多的一列

1
2
3
4
5
6
7
8
9
10
count = 0
count_max = 0
labels = ['NumRooms','Alley','Price']
for label in labels:
count = data[label].isna().sum()
if count > count_max:
count_max = count
flag = label
data_new = data.drop(flag,axis=1)
data_new
NumRoomsPrice
0NaN127500
12.0106000
24.0178100
3NaN140000

2.3 线性代数

1
import torch

2.3.1 标量

虽然直接声明常量更为常见,但是torch也支持创建标量,即长度为1的一维张量

1
2
x = torch.tensor(3.0)
y = torch.tensor(2.0)

2.3.2 向量

向量的声明

向量的声明通常就是一维张量,即tensor([x,y,z,...])

1
2
x = torch.arange(4,dtype=torch.float32)
x
tensor([0., 1., 2., 3.])
向量的形状

shape可以查看向量的维度,是一个元素组

1
2
y = torch.arange(12).reshape(2, 3, 2)
y, y.shape
(tensor([[[ 0,  1],
          [ 2,  3],
          [ 4,  5]],

         [[ 6,  7],
          [ 8,  9],
          [10, 11]]]),
 torch.Size([2, 3, 2]))

2.3.3 矩阵

声明矩阵

一个二维张量,$R^{(M·N)}$ 对应A(m,n)

1
2
A = torch.arange(20, dtype=torch.float32).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.]])
矩阵转制
1
A.T
tensor([[ 0.,  4.,  8., 12., 16.],
        [ 1.,  5.,  9., 13., 17.],
        [ 2.,  6., 10., 14., 18.],
        [ 3.,  7., 11., 15., 19.]])
按元素相乘 Hadamard Product
1
2
B = A.clone()
A * B
tensor([[  0.,   1.,   4.,   9.],
        [ 16.,  25.,  36.,  49.],
        [ 64.,  81., 100., 121.],
        [144., 169., 196., 225.],
        [256., 289., 324., 361.]])
矩阵降维
  1. 矩阵的按列降维和按行降维
1
2
3
4
A_sum_axis0 = A.sum(axis=0)
A_sum_axis1 = A.sum(axis=1)
print(A_sum_axis0, A_sum_axis0.shape)
print(A_sum_axis1, A_sum_axis1.shape)
tensor([40., 45., 50., 55.]) torch.Size([4])
tensor([ 6., 22., 38., 54., 70.]) torch.Size([5])
  1. 求平均值,按平均值降维,矩阵数据必须是dtype=torch.float32
1
A.mean(), A.mean(axis=0), A.mean(axis=1)
(tensor(9.5000),
 tensor([ 8.,  9., 10., 11.]),
 tensor([ 1.5000,  5.5000,  9.5000, 13.5000, 17.5000]))
  1. 非均值降维
1
2
sum_A = A.sum(axis=1,keepdim=True)
A, sum_A, A/sum_A
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [12., 13., 14., 15.],
         [16., 17., 18., 19.]]),
 tensor([[ 6.],
         [22.],
         [38.],
         [54.],
         [70.]]),
 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]]))
矩阵处理

按列、行累加

1
A, A.cumsum(axis=0), A.cumsum(axis=1)
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [12., 13., 14., 15.],
         [16., 17., 18., 19.]]),
 tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  6.,  8., 10.],
         [12., 15., 18., 21.],
         [24., 28., 32., 36.],
         [40., 45., 50., 55.]]),
 tensor([[ 0.,  1.,  3.,  6.],
         [ 4.,  9., 15., 22.],
         [ 8., 17., 27., 38.],
         [12., 25., 39., 54.],
         [16., 33., 51., 70.]]))

2.3.4 点乘与乘法

向量点乘

点乘等价于每个元素相乘并求和

1
2
3
y = torch.ones(4, dtype=torch.float32)
print(torch.dot(x, y))
print(torch.sum(x * y))
tensor(6.)
tensor(6.)
矩阵-向量乘法
1
torch.mv(A, x)
tensor([ 14.,  38.,  62.,  86., 110.])
矩阵-矩阵乘法
1
2
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.]])

2.3.5 范数

L1范数
1
2
u = torch.tensor([3., 4., 12.])
torch.abs(u).sum()
tensor(19.)
L2范数
1
torch.norm(u)
tensor(13.)