学习笔记
LearnAI
Chapter 1 引言
是时候系统学习一下人工智能了,希望什么时候可以补充一下引言吧
- 设备环境:Linux-Ubuntu20.04
- 编译环境:miniconda
Chapter 2 预备知识
2.1 数据处理
2.1.1 创建张量
import torch
此处为torch,虽然包叫pytorch
x = torch.arange(12)
x
tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
张量:数组,但里面的内容都是数值,维度不限
x.shape
torch.Size([12])
通过shape可以查询张量的形状;[]代表维度为1,12代表这一维度的长度
x.numel()
12
numel()可以访问张量中元素的总数
x = x.reshape(3, 4)
x
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
通过reshape(c,r),可以将张量重新排列成多维形式
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的乘积必须等于元素总数
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之外的数
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()手动构造变量
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 张量运算
基本运算
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$
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}$
张量拼接
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按列
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.
若尺寸不对应则会报错
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]])
近似于求位与运算
元素求和
x = torch.arange(12).reshape((3,4))
torch.sum(x), x.sum()
(tensor(66), tensor(66))
广播机制
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a + b
tensor([[0, 1],
[1, 2],
[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]]]))
张量切片
按行切片
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))
自定义切片
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默认最后一位
暴力写入
x[1, 2] = 9
x
tensor([[ 0, 1, 2, 3],
[ 4, 5, 9, 7],
[ 8, 9, 10, 11]])
内存节省
y = torch.arange(4)
before = id(y)
y = y + x
id(y) == before
False
在处理变量中,一般操作会导致新建内存,如果矩阵数据特别大,容易消耗内存,可以使用原地存储
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]
类型互换
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的互换
A = x.numpy()
B = torch.tensor(A)
type(A),type(B)
(numpy.ndarray, torch.Tensor)
将大小为1的张量转化为python标量
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 生成数据集文件
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文件:房价数据-房间数量/巷子类型/价格
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 补充丢失数据
补充丢失数据的典型方法是插值法和删除法
- 插值法:用一个数字替代缺失位
- 删除法:直接忽略缺少的数据
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()读取数据平均数
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 转化为张量形式
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()构造张量
实例:删除空数据最多的一列
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
| NumRooms | Price | |
|---|---|---|
| 0 | NaN | 127500 |
| 1 | 2.0 | 106000 |
| 2 | 4.0 | 178100 |
| 3 | NaN | 140000 |
2.3 线性代数
import torch
2.3.1 标量
虽然直接声明常量更为常见,但是torch也支持创建标量,即长度为1的一维张量
x = torch.tensor(3.0)
y = torch.tensor(2.0)
2.3.2 向量
向量的声明
向量的声明通常就是一维张量,即tensor([x,y,z,...])
x = torch.arange(4,dtype=torch.float32)
x
tensor([0., 1., 2., 3.])
向量的形状
shape可以查看向量的维度,是一个元素组
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)
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.]])
矩阵转制
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
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.]])
矩阵降维
- 矩阵的按列降维和按行降维
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])
2. 求平均值,按平均值降维,矩阵数据必须是dtype=torch.float32
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]))
3. 非均值降维
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]]))
矩阵处理
按列、行累加
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 点乘与乘法
向量点乘
点乘等价于每个元素相乘并求和
y = torch.ones(4, dtype=torch.float32)
print(torch.dot(x, y))
print(torch.sum(x * y))
tensor(6.)
tensor(6.)
矩阵-向量乘法
torch.mv(A, x)
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.]])
2.3.5 范数
L1范数
$$ ||x||1 = \sum{i=1}^{n}{|x_i|} $$
u = torch.tensor([3., 4., 12.])
torch.abs(u).sum()
tensor(19.)
L2范数
$$ norm = ||x||2 = \sqrt{\sum{i=1}^{n}{x_i^2}} $$
torch.norm(u)
tensor(13.)