跳至主要內容

动手学深度学习

pptg大约 3 分钟

跟沐神学open in new window 吼吼吼,上学不跟沐神好好学,上班之后来换债了

原文里的conda,这里会换成uv,如果遇到问题再说吧,uv实在是太快了

1. 深度学习基础

1.1 环境安装

这里推荐是用GPU,我用的MAC,所以先用CPU顶一下,后面遇到需要GPU的地方再去租云GPU吧

# 新建项目
mkdir ml_learn
cd ml_learn

# uv初始化
uv init

# 添加环境
uv add jupyter
uv add torch
uv add pandas
uv add matplotlib
uv add d2l
uv add torchvision


# 下载D2L
curl https://zh-v2.d2l.ai/d2l-zh-2.0.0.zip -o d2l-zh.zip
unzip d2l-zh.zip && rm d2l-zh.zip

1.2 数据操作

  • 张量的原地更新: 计算tensor的时候,Y、X会先计算,并分配一个内存,最后将Y指向新的内存。
非原地更新
before = id(Y)
Y = Y + X
id(Y) == before
# False

1.3 数据预处理

1.3.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')
    
# pandas读取
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

1.3.2 处理缺失值

处理原数据集的NaN部分,用平均值替换

inputs, outputs = data.iloc[:, 0:2], data.iloc[:, 2]
inputs["NumRooms"] = inputs["NumRooms"].fillna(inputs["NumRooms"].mean())
print(inputs)

1.3.3 One-Hot编码

将非数值列,转换为One-Hot编码,便于转换为张量

  • 机器学习兼容性:大多数机器学习算法只能处理数值数据
  • 避免顺序误解:防止算法误以为类别之间有大小关系
  • 保留缺失值信息:将缺失值作为有用信息而非直接丢弃
inputs = pd.get_dummies(inputs, dummy_na=True)
print(inputs)

# (tensor([[3., 1., 0.],
#          [2., 0., 1.],
#          [4., 0., 1.],
#          [3., 0., 1.]], dtype=torch.float64),
# tensor([127500, 106000, 178100, 140000]))

1.3.4 转换为张量

将数值转换为张量,便于后续张量计算

import torch

x = torch.tensor(inputs.to_numpy(dtype=float))
y = torch.tensor(outputs.to_numpy(dtype=float))
x, y

2. 预备知识

2.1 自动微分

2.1.1 标量的反向传播

y=2xx的列向量x求导:

  • 使用requires_grad_来设置张量计算梯度
  • 使用backward,会从调用的张量开始,沿着计算图反向传播,计算所有requires_grad=True的张量的梯度
import torch

x = torch.arange(4.0)
# tensor([0., 1., 2., 3.])

x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)
x.grad  # 默认值是None

y = 2 * torch.dot(x, x)
# tensor(28., grad_fn=<MulBackward0>)

y.backward()
x.grad
# tensor([ 0.,  4.,  8., 12.])

2.1.2 非标量的反向传播

如果y不是一个标量(1*1),需要先将它转换成标量,可以用sum直接求和,也可以成一个ones相加。

x.grad.zero_()
y = x * x
# tensor([0., 1., 4., 9.], grad_fn=<MulBackward0>)

# 等价于y.backward(torch.ones(len(x)))
y.sum().backward()
# tensor([0., 2., 4., 6.])

3. 线性神经网络