数据加载 torchvision.datasets
1. 内置数据集
内置数据集的形式均为 ((x_train, y_train), (x_test, y_test)),x 为自变量,y 为因变量。获取数据集时需要调用 load_data()。
CIFAR10
CIFAR10 小图像分类数据集。
import torch
from torchvision import datasets, transforms
# 定义数据转换,这里我们只做归一化处理
transform = transforms.Compose([
transforms.ToTensor(), # 转换为 Tensor
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 归一化
])
# 下载并加载训练集
trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
# 下载并加载测试集
testset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
# 获取训练集的数据和标签
x_train, y_train = trainset.data, trainset.targets
# 获取测试集的数据和标签
x_test, y_test = testset.data, testset.targets
# 打印一些信息以确认数据加载成功
print("Train data shape:", x_train.shape)
print("Train labels shape:", len(y_train))
print("Test data shape:", x_test.shape)
print("Test labels shape:", len(y_test))
CIFAR100
CIFAR100 小图像分类数据集。
import torch
from torchvision import datasets, transforms
# 定义数据预处理步骤
transform = transforms.Compose([
transforms.ToTensor(), # 转换为张量
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 标准化
])
# 下载并加载训练数据集
train_dataset = datasets.CIFAR100(root='./data', train=True, download=True, transform=transform)
x_train, y_train = train_dataset.data, train_dataset.targets
# 下载并加载测试数据集
test_dataset = datasets.CIFAR100(root='./data', train=False, download=True, transform=transform)
x_test, y_test = test_dataset.data, test_dataset.targets
# 显示数据形状
print("Training data shape:", x_train.shape)
print("Training labels shape:", len(y_train))
print("Test data shape:", x_test.shape)
print("Test labels shape:", len(y_test))
FashionMNIST
时尚 MNIST 数据集。
import torch
from torchvision import datasets, transforms
# 定义数据预处理步骤
transform = transforms.Compose([
transforms.ToTensor(), # 转换为 Tensor
transforms.Normalize((0.5,), (0.5,)) # 归一化到 [-1, 1]
])
# 下载并加载训练数据集
trainset = datasets.FashionMNIST('~/.pytorch/F_MNIST_data/', download=True, train=True, transform=transform)
x_train, y_train = trainset.data, trainset.targets
# 下载并加载测试数据集
testset = datasets.FashionMNIST('~/.pytorch/F_MNIST_data/', download=True, train=False, transform=transform)
x_test, y_test = testset.data, testset.targets
MNIST
MNIST 手写数字数据集。
import torch
from torchvision import datasets, transforms
# 定义数据预处理步骤
transform = transforms.Compose([
transforms.ToTensor(), # 转换为 Tensor
transforms.Normalize((0.1307,), (0.3081,)) # 使用 MNIST 数据集的均值和方差
])
# 下载并加载训练数据集
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
x_train, y_train = trainset.data, trainset.targets
# 下载并加载测试数据集
testset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
x_test, y_test = testset.data, testset.targets
2. 数据集 Dataset 的创建
输入 list 数据创建数据集
import torch
from torch.utils.data import Dataset
class ListDataset(Dataset):
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 示例数据
features = [[1, 2], [3, 4], [5, 6]]
labels = [0, 1, 2]
dataset = ListDataset(features, labels)
输入 numpy 的 ndarray 转换为数据集
import numpy as np
from torch.utils.data import Dataset
class ArrayDataset(Dataset):
def __init__(self, df):
self.features = df[:, 0:-1].astype('float32')
self.labels = df[:, -1].astype('float32')
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
# ndarray 类型使用 torch.from_numpy 解析为 tensor,单个数值使用 torch.tensor 解析为 tensor
return {'feature': torch.from_numpy(feature), 'label': torch.tensor(label)}
# 示例数据
array = np.array([
[1, 3, 5, 1],
[2, 4, 6, 0],
[0, 1, 2, 1]
])
dataset = ArrayDataset(array)
输入 pandas 的 DataFrame 转换为数据集
import pandas as pd
from torch.utils.data import Dataset
class DataFrameDataset(Dataset):
def __init__(self, df):
# 注意:DataFrame 特性,一次性选择多列,返回 DataFrame;一次性选择单列,返回 Series;
# 注意:DataFrame 和 Series 调用 .values 都会返回 numpy.ndarray
self.features = df.iloc[:, :-1].values.astype('float32')
self.labels = df.iloc[:, -1].values.astype('int')
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature), 'label': torch.tensor(label)}
# 示例数据
df = pd.DataFrame({
'feature1': [1, 3, 5],
'feature2': [2, 4, 6],
'label': [0, 1, 2]
})
dataset = DataFrameDataset(df)
读取 csv 文件
import pandas as pd
from torch.utils.data import Dataset
class CSVDataset(Dataset):
def __init__(self, csv_file):
self.df = pd.read_csv(csv_file)
self.features = self.df.iloc[:, :-1].values.astype('float32')
self.labels = self.df.iloc[:, -1].values.astype('int')
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature), 'label': torch.tensor(label)}
# CSV 文件路径
csv_file = 'path/to/your/data.csv'
dataset = CSVDataset(csv_file)
读取文本文件
import torch
from torch.utils.data import Dataset
class TextFileDataset(Dataset):
def __init__(self, text_file):
self.lines = []
with open(text_file, 'r') as f:
for line in f:
parts = line.strip().split(',')
feature = list(map(float, parts[:-1]))
label = int(parts[-1])
self.lines.append((feature, label))
def __len__(self):
return len(self.lines)
def __getitem__(self, idx):
feature, label = self.lines[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 文本文件路径
text_file = 'path/to/your/data.txt'
dataset = TextFileDataset(text_file)
读取二进制文件
import torch
from torch.utils.data import Dataset
import numpy as np
class BinaryFileDataset(Dataset):
def __init__(self, binary_file):
self.data = np.fromfile(binary_file, dtype=np.float32)
self.features = self.data[:-1]
self.labels = self.data[-1]
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 二进制文件路径
binary_file = 'path/to/your/data.bin'
dataset = BinaryFileDataset(binary_file)
创建有序数组 Tensor
start = 0
end = 10
step = 1
range_tensor = torch.arange(start, end, step)
print(range_tensor) # 输出:tensor([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
读取语音文件
import torch
import os
from torch.utils.data import Dataset
import torchaudio
class AudioFolderDataset(Dataset):
def __init__(self, audio_dir):
self.audio_dir = audio_dir
self.file_list = os.listdir(audio_dir)
def __len__(self):
return len(self.file_list)
def __getitem__(self, idx):
file_path = os.path.join(self.audio_dir, self.file_list[idx])
waveform, sample_rate = torchaudio.load(file_path)
# 假设标签存储在文件名中或其他地方
label = int(self.file_list[idx].split('.')[0]) # 示例假设文件名为 label.wav
return {'waveform': waveform, 'label': torch.tensor(label)}
# 音频文件夹路径
audio_dir = 'path/to/your/audio_folder'
dataset = AudioFolderDataset(audio_dir)
读取图像文件
import torch
import os
from torch.utils.data import Dataset
from torchvision import transforms
from PIL import Image
class ImageFolderDataset(Dataset):
def __init__(self, img_dir, transform=None):
self.img_dir = img_dir
self.file_list = os.listdir(img_dir)
self.transform = transform
def __len__(self):
return len(self.file_list)
def __getitem__(self, idx):
img_path = os.path.join(self.img_dir, self.file_list[idx])
image = Image.open(img_path).convert('RGB')
if self.transform:
image = self.transform(image)
# 假设标签存储在文件名中或其他地方
label = int(self.file_list[idx].split('.')[0]) # 示例假设文件名为 label.jpg
return {'image': image, 'label': torch.tensor(label)}
# 图像文件夹路径
img_dir = 'path/to/your/image_folder'
# 数据增强
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
dataset = ImageFolderDataset(img_dir, transform=transform)
读取文本文件目录
import torch
import os
from torch.utils.data import Dataset
class TextFolderDataset(Dataset):
def __init__(self, text_dir):
self.text_dir = text_dir
self.file_list = os.listdir(text_dir)
def __len__(self):
return len(self.file_list)
def __getitem__(self, idx):
file_path = os.path.join(self.text_dir, self.file_list[idx])
with open(file_path, 'r') as f:
text = f.read()
# 假设标签存储在文件名中或其他地方
label = int(self.file_list[idx].split('.')[0]) # 示例假设文件名为 label.txt
return {'text': text, 'label': torch.tensor(label)}
# 文本文件夹路径
text_dir = 'path/to/your/text_folder'
dataset = TextFolderDataset(text_dir)
3. 数据集 Dataset 的拆分、合并
单个数据集拆分为训练集和测试集(Subset)
# 假设有一个简单的 ListDataset 类,用于从一个列表中读取数据
import torch
from torch.utils.data import Dataset
class ListDataset(Dataset):
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 示例数据
features = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
labels = [0, 1, 2, 3, 4]
# 创建 Dataset 实例
dataset = ListDataset(features, labels)
# 使用随机抽样的方式来拆分数据集
import random
import torch
from torch.utils.data import Subset
# 设置随机种子以保证结果的一致性
random.seed(42)
# 指定拆分比例
train_ratio = 0.8
test_ratio = 1 - train_ratio
# 获取数据集的长度
total_length = len(dataset)
# 计算训练集和测试集的大小
train_length = int(total_length * train_ratio)
test_length = total_length - train_length
# 生成索引,随机打乱
indices = list(range(total_length))
random.shuffle(indices)
# 拆分索引
train_indices = indices[:train_length]
test_indices = indices[train_length:]
# 创建训练集和测试集,Subset 根据输入的索引生成子集
train_dataset = Subset(dataset, train_indices)
test_dataset = Subset(dataset, test_indices)
# 使用 DataLoader 来加载拆分后的数据集
from torch.utils.data import DataLoader
# 定义批量大小
batch_size = 2
# 创建 DataLoader 实例
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
# 验证输出
for batch in train_loader:
print(batch)
break
for batch in test_loader:
print(batch)
break
多个数据集以抽样的方式合并
# 定义多个数据集
import torch
from torch.utils.data import Dataset
class SimpleDataset(Dataset):
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 创建几个数据集实例
dataset1 = SimpleDataset([[1, 2], [3, 4]], [0, 1])
dataset2 = SimpleDataset([[5, 6], [7, 8]], [2, 3])
dataset3 = SimpleDataset([[9, 10], [11, 12]], [4, 5])
# 使用 ConcatDataset 来合并这些数据集
from torch.utils.data import ConcatDataset
# 合并数据集
combined_dataset = ConcatDataset([dataset1, dataset2, dataset3])
# 定义采样策略
from torch.utils.data import Sampler
class RandomBatchSampler(Sampler):
def __init__(self, source_sampler, batch_size, drop_last):
self.source_sampler = source_sampler
self.batch_size = batch_size
self.drop_last = drop_last
def __iter__(self):
batch = []
for idx in self.source_sampler:
batch.append(idx)
if len(batch) == self.batch_size:
yield batch
batch = []
if len(batch) > 0 and not self.drop_last:
yield batch
def __len__(self):
if self.drop_last:
return len(self.source_sampler) // self.batch_size
else:
return (len(self.source_sampler) + self.batch_size - 1) // self.batch_size
# 创建一个随机采样器
random_sampler = torch.utils.data.RandomSampler(combined_dataset)
# 使用自定义的 RandomBatchSampler
batch_size = 2
drop_last = True
batch_sampler = RandomBatchSampler(random_sampler, batch_size, drop_last)
# 使用 DataLoader 来加载数据
from torch.utils.data import DataLoader
# 创建 DataLoader 实例
data_loader = DataLoader(combined_dataset, batch_sampler=batch_sampler)
# 验证输出
for batch in data_loader:
print(batch)
多个数据集进行串联合并
# 创建多个数据集
import torch
from torch.utils.data import Dataset
class SimpleDataset(Dataset):
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 创建几个数据集实例
dataset1 = SimpleDataset([[1, 2], [3, 4]], [0, 1])
dataset2 = SimpleDataset([[5, 6], [7, 8]], [2, 3])
dataset3 = SimpleDataset([[9, 10], [11, 12]], [4, 5])
# 使用 ConcatDataset 来串联这些数据集:
from torch.utils.data import ConcatDataset
# 串联数据集
combined_dataset = ConcatDataset([dataset1, dataset2, dataset3])
# 使用 DataLoader 来加载串联后的数据集
from torch.utils.data import DataLoader
# 定义批量大小
batch_size = 2
# 创建 DataLoader 实例
data_loader = DataLoader(combined_dataset, batch_size=batch_size, shuffle=True)
# 验证输出
for batch in data_loader:
print(batch)
多个数据集进行拉链合并
# 创建多个数据集
import torch
from torch.utils.data import Dataset
class SimpleDataset(Dataset):
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 创建几个数据集实例
dataset1 = SimpleDataset([[1, 2], [3, 4]], [0, 1])
dataset2 = SimpleDataset([[5, 6], [7, 8]], [2, 3])
dataset3 = SimpleDataset([[9, 10], [11, 12]], [4, 5])
# 自定义的 Sampler 类来实现"拉链"效果
from torch.utils.data import Sampler
import numpy as np
class ZipSampler(Sampler):
def __init__(self, datasets):
self.datasets = datasets
self.lengths = [len(d) for d in datasets]
self.total_length = sum(self.lengths)
def __iter__(self):
iterators = [iter(range(len(d))) for d in self.datasets]
combined_indices = []
max_index = max(self.lengths)
for i in range(max_index):
for j, it in enumerate(iterators):
if i < self.lengths[j]:
combined_indices.append((j, next(it)))
np.random.shuffle(combined_indices) # 可选:随机打乱顺序
return iter([idx for _, idx in sorted(combined_indices)])
def __len__(self):
return self.total_length
# 使用 DataLoader 并传入自定义的 ZipSampler 来加载数据
from torch.utils.data import DataLoader
# 创建 DataLoader 实例
batch_size = 1 # 由于是拉链合并,这里设置批量大小为 1
data_loader = DataLoader(
dataset1, # 使用第一个数据集作为占位符,实际数据由 Sampler 提供
batch_size=batch_size,
sampler=ZipSampler([dataset1, dataset2, dataset3]),
collate_fn=lambda batch: batch # 自定义拼接函数
)
# 验证输出
for batch in data_loader:
print(batch)
4. 数据集 Dataset 的查看
查看 Dataset 的内容
# 查看前几个元素的值
for i in range(min(5, len(dataset))):
print(f"Element {i}: {dataset[i]}")
查看 Dataset 的 Tensor 的内容
for i in range(min(5, len(dataset))):
element = dataset[i]
print(f"Element {i} contains:")
for key, value in element.items():
print(f" {key}: {value}")
查看 Dataset 大小(元素数量)
print(f"Dataset size: {len(dataset)}")
查看 dataset 中每个 batch 的内容
from torch.utils.data import DataLoader
batch_size = 2
data_loader = DataLoader(dataset, batch_size=batch_size, shuffle=False)
# 查看前几个 batch 的内容
for i, batch in enumerate(data_loader):
if i >= 5:
break
print(f"Batch {i}:")
for j, element in enumerate(batch):
print(f" Batch Element {j}:")
for key, value in element.items():
print(f" {key}: {value}")
查看数据集结构
仅查看元素的结构、类型、形状:
# 查看前几个元素的结构
for i in range(min(5, len(dataset))):
element = dataset[i]
print(f"Element {i} structure:")
for key, value in element.items():
print(f" {key}: type={type(value)}, shape={value.shape if isinstance(value, torch.Tensor) else None}")
5. 数据集 Dataset 的元素
torch 的 dataset 中可以存放任意类型元素。
import torch
from torch.utils.data import Dataset
class MixedTypeDataset(Dataset):
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
return self.data[idx]
class Sample:
def __init__(self, data1, data2):
self.data1 = data1
self.data2 = data2
def __repr__(self):
return f"data1:{self.data1}, data2:{self.data2}"
# 示例数据
data = [
(torch.tensor([1.0, 2.0]), torch.tensor(0)), # 元组
{'feature': torch.tensor([3.0, 4.0]), 'label': torch.tensor(1)}, # 字典
[torch.tensor([5.0, 6.0]), torch.tensor(2)], # 列表
Sample(torch.tensor([7.0, 8.0]), torch.tensor(3)) # 自定义类的对象
]
# 创建 Dataset 实例
dataset = MixedTypeDataset(data)
# 查看前几个元素
for i in range(min(5, len(dataset))):
print(f"Element {i}: {dataset[i]}")
6. 数据集 Dataset 的转换
和 TensorFlow 不同,Torch 要求对单个样本具有访问能力,因此 dataset 的转换有较大差异。
map 操作
在 __getitem__ 方法中实现,或者在创建 DataLoader 时使用 collate_fn 函数来实现。
import torch
from torch.utils.data import Dataset, DataLoader
class SimpleDataset(Dataset):
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': feature, 'label': label}
def transform_batch(batch):
# 假设 batch 是一个列表,其中每个元素都是一个字典 {'feature': ..., 'label': ...}
transformed_batch = []
for item in batch:
# 对 feature 应用一个变换
transformed_feature = item['feature'] * 2
transformed_batch.append({'feature': transformed_feature, 'label': item['label']})
return transformed_batch
# 创建数据集
features = [[1, 2], [3, 4], [5, 6]]
labels = [0, 1, 2]
dataset = SimpleDataset(features, labels)
# 创建 DataLoader 并使用自定义的 collate_fn
# collate_fn 遍历每一个 batch,对每个元素进行处理
data_loader = DataLoader(dataset, batch_size=2, collate_fn=transform_batch)
# 验证输出
for batch in data_loader:
print(batch)
filter 操作
根据条件过滤元素:
class FilteredDataset(Dataset):
def __init__(self, base_dataset, condition_func):
self.base_dataset = base_dataset
self.indices = [i for i in range(len(base_dataset)) if condition_func(base_dataset[i])]
def __len__(self):
return len(self.indices)
def __getitem__(self, idx):
return self.base_dataset[self.indices[idx]]
def filter_condition(item):
return item['label'] % 2 == 0
filtered_dataset = FilteredDataset(dataset, filter_condition)
# 创建 DataLoader
data_loader = DataLoader(filtered_dataset, batch_size=2)
# 验证输出
for batch in data_loader:
print(batch)
batch 操作
数据分批,通过 DataLoader 类实现:
# 创建 DataLoader 并指定 batch_size
data_loader = DataLoader(dataset, batch_size=2)
# 验证输出
for batch in data_loader:
print(batch)
shuffle 操作
随机打乱数据,在创建 DataLoader 时设置 shuffle=True 来实现:
# 创建 DataLoader 并启用 shuffle
data_loader = DataLoader(dataset, batch_size=2, shuffle=True)
# 验证输出
for batch in data_loader:
print(batch)
7. 数据集 Dataset 的遍历
遍历 Dataset
import torch
from torch.utils.data import Dataset
class SimpleDataset(Dataset):
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self):
return len(self.features)
def __getitem__(self, idx):
feature = self.features[idx]
label = self.labels[idx]
return {'feature': torch.tensor(feature, dtype=torch.float), 'label': torch.tensor(label)}
# 创建数据集实例
features = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
labels = [0, 1, 2, 3, 4]
dataset = SimpleDataset(features, labels)
# 直接遍历数据集
for i, sample in enumerate(dataset):
print(f"Sample {i}: {sample}")
from torch.utils.data import DataLoader
# 创建 DataLoader 实例
batch_size = 2
data_loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
遍历 DataLoader 返回的 Dataset
# 使用 DataLoader 遍历数据集
for batch_idx, batch in enumerate(data_loader):
features = batch['feature']
labels = batch['label']
print(f"Batch {batch_idx}: Features shape: {features.shape}, Labels shape: {labels.shape}")
8. 数据集 Dataset 的性能优化——DataLoader 参数配置
使用多线程/多进程(num_workers)
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True,
num_workers=4, # 设置子进程数量
pin_memory=True,
drop_last=True
)
注意:保证数据顺序不变的方法如下:
方法 1:禁用多线程/多进程,设置 num_workers=0:
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=False,
num_workers=0, # 禁用多线程/多进程
pin_memory=True,
drop_last=True # 当最后一个 batch 不满足指定的 batch_size 时,丢弃最后一个 batch
)
方法 2:使用 SequentialSampler。如果设置了 shuffle=False 且 num_workers > 0,可以显式地使用 SequentialSampler 来确保数据顺序不变:
from torch.utils.data import SequentialSampler
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=False,
num_workers=4,
pin_memory=True,
drop_last=True,
sampler=SequentialSampler(dataset)
)
方法 3:自定义 Sampler。如果需要更复杂的顺序控制,可以自定义 Sampler 来实现特定的顺序规则:
from torch.utils.data import Sampler
class FixedOrderSampler(Sampler):
def __init__(self, data_source):
self.data_source = data_source
def __iter__(self):
return iter(range(len(self.data_source)))
def __len__(self):
return len(self.data_source)
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=False,
num_workers=4,
pin_memory=True,
drop_last=True,
sampler=FixedOrderSampler(dataset)
)
设置 pin_memory
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True,
num_workers=4,
pin_memory=True, # 将数据加载到固定内存区域(pinned memory),以便更快地传输到 GPU
drop_last=True
)
数据预处理
from torchvision.transforms import ToTensor, Normalize
transform = transforms.Compose([
ToTensor(),
Normalize(mean=[0.5], std=[0.5])
])
class ImageDataset(Dataset):
def __init__(self, data_dir, transform=None):
self.data_dir = data_dir
self.transform = transform
# 加载数据集...
def __len__(self):
return len(self.data)
def __getitem__(self, index):
image_path = os.path.join(self.data_dir, f'image_{index}.jpg')
image = Image.open(image_path).convert('RGB')
if self.transform:
image = self.transform(image)
return image, self.labels[index]
使用 CacheDataset 缓存数据
class CacheDataset(Dataset):
def __init__(self, base_dataset):
super(CacheDataset, self).__init__()
self.base_dataset = base_dataset
self.cache = [self.base_dataset[i] for i in range(len(self.base_dataset))]
def __len__(self):
return len(self.base_dataset)
def __getitem__(self, index):
return self.cache[index]
数据并行处理
def worker_init_fn(worker_id):
np.random.seed(worker_id + (int(torch.ones(1).item()) * 100000))
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True,
num_workers=4,
pin_memory=True,
drop_last=True,
worker_init_fn=worker_init_fn # 使用 num_workers 大于 1 时,可以设置 worker_init_fn 来初始化子进程,确保每个子进程有不同的随机种子
)
使用 prefetch_factor
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True,
num_workers=4,
pin_memory=True,
drop_last=True,
prefetch_factor=4 # 默认为 2,prefetch_factor 参数指定了每个工作进程提前加载的批次数量。增加这个参数可以减少等待时间
)
使用 persistent_workers
data_loader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True,
num_workers=4,
pin_memory=True,
drop_last=True,
persistent_workers=True # 设置 persistent_workers=True 可以让子进程在整个训练过程中持续存在,避免频繁启动和销毁子进程带来的开销
)
使用 torchvision 中的预定义数据集
预定义的数据集类已经进行了大量的优化:
from torchvision import datasets, transforms
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.5], std=[0.5])
])
trainset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=4)
9. 张量 Tensor 的重构
张量形状
import torch
# 创建一个形状为 [3, 4] 的张量
tensor = torch.randn(3, 4)
print(tensor.shape) # 输出: torch.Size([3, 4])
张量元素数量
print(tensor.numel()) # 输出: 12
张量的阶数
print(len(tensor.shape)) # 输出: 2
print(tensor.ndim) # 输出: 2
使用 .reshape() 方法
# 创建一个形状为 [4, 5] 的张量
tensor = torch.randn(4, 5)
# 将张量重塑为 [2, 10]
reshaped_tensor = tensor.reshape(2, 10)
print(reshaped_tensor.size()) # 输出: torch.Size([2, 10])
使用 .view() 方法
import torch
# 创建一个形状为 (10, 3, 28, 28) 的张量
x = torch.randn(10, 3, 28, 28)
# 展平张量为 (10, 3 * 28 * 28)
x_flat = x.view(10, -1)
print(x.shape) # 输出:torch.Size([10, 3, 28, 28])
print(x_flat.shape) # 输出:torch.Size([10, 2352])
使用 .unsqueeze() 和 .squeeze() 方法
增加或减少维度:
# 创建一个形状为 [4, 5] 的张量
tensor = torch.randn(4, 5)
# 增加一个维度,变成 [1, 4, 5]
unsqueezed_tensor = tensor.unsqueeze(0)
print(unsqueezed_tensor.size()) # 输出: torch.Size([1, 4, 5])
# 减少一个维度,如果有一个维度大小为 1,则被剔除
squeezed_tensor = unsqueezed_tensor.squeeze(0)
print(squeezed_tensor.size()) # 输出: torch.Size([4, 5])
转置
使用 .t():
tensor = torch.randn(3, 4)
transposed_tensor = tensor.t()
print(transposed_tensor.size()) # 输出: torch.Size([4, 3])
使用 .transpose() 改变维度顺序:
tensor = torch.randn(3, 4, 5)
# 交换第一维和第三维的位置
transposed_tensor = tensor.transpose(0, 2)
print(transposed_tensor.size()) # 输出: torch.Size([5, 4, 3])
使用 .permute() 改变维度顺序:
tensor = torch.randn(2, 3, 4, 5)
# 重新排列维度为 [2, 4, 3, 5]
permuted_tensor = tensor.permute(0, 2, 1, 3)
print(permuted_tensor.size()) # 输出: torch.Size([2, 4, 3, 5])
堆叠
假设有 N 个张量,形状为 (A, B, C)。
x = torch.tensor([1, 4], requires_grad=False)
y = torch.tensor([2, 5], requires_grad=False)
z = torch.tensor([3, 6], requires_grad=False)
横向拼接,形成新的数据集 (N, A, B, C),axis=0:
# 使用 torch.stack 来横向拼接张量
# dim=0 表示在第一个维度上拼接,这相当于横向拼接
horizontal_tensors = torch.stack([x, y, z], dim=0)
print(horizontal_tensors.size())
纵向堆叠,形成新的数据集 (A, N, B, C),axis=1:
# 使用 torch.stack 来纵向堆叠张量
# dim=1 表示在第二个维度上堆叠,这相当于纵向堆叠
vertical_tensors = torch.stack([tensor1, tensor2, tensor3], dim=1)
print(vertical_tensors.size())
连接
沿着指定的轴连接多个张量。
顺序索引,axis=0:
import torch
t1 = torch.randn(3)
t2 = torch.randn(3)
t1 = t1.unsqueeze(0)
t2 = t2.unsqueeze(0)
stacked_tensors = torch.cat((t1, t2), dim=1) # 在第 0 维度上拼接
print(t1)
print(t2)
print(stacked_tensors)
倒序索引,axis=-1:
import torch
t1 = torch.randn(3)
t2 = torch.randn(3)
t1 = t1.unsqueeze(0)
t2 = t2.unsqueeze(0)
stacked_tensors = torch.cat((t1, t2), dim=-1) # 在第 -1 维度上拼接
print(t1)
print(t2)
print(stacked_tensors)
平铺
将第一个张量,按照第二个张量,进行平铺:
import torch
# 创建一个简单的张量
tensor = torch.tensor([[1, 2], [3, 4]])
# 指定每个维度上的重复次数
# dims=(2, 3) 表示沿着第一个维度重复 2 次,沿着第二个维度重复 3 次
tiled_tensor = torch.tile(tensor, (2, 3))
print(tiled_tensor)
重复
沿指定轴对元素进行复制,返回一个行向量:
tensor = torch.tensor([1, 2, 3])
repeated_tensor = tensor.repeat_interleave(2) # 每个元素重复两次
print(repeated_tensor) # 输出: tensor([1, 1, 2, 2, 3, 3])
10. 创建张量
注意:创建张量,务必指定
dtype类型,否则可能在代码执行过程中报错。
使用常数创建张量 torch.tensor
import torch
# 创建一个标量(0-D)张量
scalar = torch.tensor(5)
# 创建一个向量(1-D)张量
vector = torch.tensor([1, 2, 3])
# 创建一个矩阵(2-D)张量
matrix = torch.tensor([[1, 2, 3], [4, 5, 6]])
使用 list 数组创建张量 torch.tensor
data_list = [1, 2, 3]
tensor_from_list = torch.tensor(data_list, dtype=torch.int)
使用 numpy 数组创建张量 torch.from_numpy
import numpy as np
# 创建一个 Numpy 数组
numpy_array = np.array([[1, 2, 3], [4, 5, 6]])
# 转换为 torch 张量
tensor_from_numpy = torch.from_numpy(numpy_array)
通用的创建张量方式 torch.as_tensor
# 从 list 创建张量
data_list = [1, 2, 3]
tensor_from_list = torch.as_tensor(data_list, dtype=torch.float32)
# 从 numpy 创建张量
numpy_array = np.array([1, 2, 3])
tensor_from_numpy = torch.as_tensor(numpy_array, dtype=torch.float32)
# 创建多维张量
data_2d = [[1, 2], [3, 4]]
tensor_2d = torch.as_tensor(data_2d)
使用随机数生成张量
标准正态分布随机张量 torch.randn:
# 创建一个标准正态分布随机张量
random_normal_tensor = torch.randn(2, 3)
正态分布随机张量:
# 创建一个正态分布随机张量
mean = torch.tensor([1.0, 2.0, 3.0])
std = torch.tensor([0.5, 0.5, 0.5])
custom_normal_tensor = torch.normal(mean=mean, std=std)
均匀随机分布张量:
import torch
# 创建一个形状为 [2, 3] 的均匀分布张量(范围在 [0, 1))
uniform_tensor = torch.rand(2, 3)
print(uniform_tensor)
# 创建一个范围在 [a, b) 之间的均匀分布张量
a = 0
b = 5
custom_uniform_tensor = (b - a) * torch.rand(2, 3) + a
print(custom_uniform_tensor)
使用特定形状创建张量
# 创建一个全零张量
zeros_tensor = torch.zeros(2, 3)
# 创建一个全一张量
ones_tensor = torch.ones(2, 3)
# 创建一个空张量
empty_tensor = torch.empty(2, 3)
# 创建单位矩阵
eye_tensor = torch.eye(2)
使用序列生成张量 torch.arange
# 创建一个等差数列张量
range_tensor = torch.arange(start=0, end=5, step=2)
11. 张量类型
# 常量张量
constant_tensor = torch.tensor([[1, 2, 3], [4, 5, 6]], requires_grad=False)
# 创建指定形状的常量张量
constant_tensor_full = torch.full((2, 3), 1.0)
# 变量张量
variable_tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]], requires_grad=True)
12. 张量计算
加法(torch.add)
# 创建两个张量,形状不同会进行广播
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
# 使用 torch.add 执行加法
result = torch.add(a, b)
result = a + b
减法(torch.subtract)
# 创建两个张量,形状不同会进行广播
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
# 使用 torch.subtract 执行减法
result = torch.subtract(a, b)
result = a - b
乘法(torch.multiply)
# 创建两个张量
a = torch.tensor([1, 2, 3])
b = torch.tensor([[4], [5], [6]])
# 使用 torch.multiply 执行元素级乘法,点积,形状不同会进行广播
result = torch.multiply(a, b)
result = a * b
除法(torch.divide)
# 创建两个张量
a = torch.tensor([1, 2, 3])
b = torch.tensor(4)
# 使用 torch.divide 执行除法,形状不同会进行广播
result = torch.divide(a, b)
result = a / b
幂运算(torch.pow)
# 创建两个张量
a = torch.tensor([1, 2, 3])
b = torch.tensor(4)
# 使用 torch.pow 执行幂运算
result = torch.pow(a, b)
result = a ** b
指数(torch.exp)
# 创建两个张量
a = torch.tensor([1, 2, 3])
b = torch.tensor(4)
# 使用 torch.exp 执行指数运算
result = torch.exp(a, b)
矩阵乘法(torch.matmul)
# 创建两个张量
a = torch.tensor([[1, 2], [3, 4]])
b = torch.tensor([[5, 6], [7, 8]])
# 使用 torch.matmul 执行矩阵乘法
result = torch.matmul(a, b)
result = a @ b
13. 张量的梯度
梯度缓存清零(optimizer.zero_grad)
- 梯度清零:在每次前向传播之后和反向传播之前,需要清除之前累积的梯度。
- 防止梯度累积:如果不清除梯度,那么在多次反向传播过程中,梯度会累积起来,可能导致错误的结果。
optimizer.zero_grad()是将model.parameters().grad属性中的值重置为 0。
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
optimizer.zero_grad() # 清除梯度
outputs = model(inputs) # 预测
loss = criterion(outputs, targets) # 计算损失度
loss.backward() # 计算梯度
optimizer.step() # 更新权重
禁用梯度计算(torch.no_grad)
用于禁用梯度计算。在不需要梯度计算的场景下(如推理、评估等),使用 no_grad() 可以提高性能并减少内存使用:
model.eval()
with torch.no_grad():
output = model(input_tensor)
模型构建 torch.nn
1. 容器 torch.nn.Module
所有模型的基类,__init__ 方法中每增加一层,都会新增一个子模型。
import torch.nn as nn
import torch.nn.functional as F
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.conv1 = nn.Conv2d(1, 20, 5) # 子模型: Conv2d
self.conv2 = nn.Conv2d(20, 20, 5)
def forward(self, x):
x = F.relu(self.conv1(x))
return F.relu(self.conv2(x))
add_module
增加一个子模型。
import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.add_module("conv", nn.Conv2d(10, 20, 4))
# self.conv = nn.Conv2d(10, 20, 4) 和上面这个增加 module 的方式等价
model = Model()
print(model.conv)
children
递归查看所有子模型,不重复。
import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.add_module("conv", nn.Conv2d(10, 20, 4))
self.add_module("conv1", nn.Conv2d(20, 10, 4))
model = Model()
for sub_module in model.children():
print(sub_module)
其他常用方法
| 方法 | 说明 |
|---|---|
cpu(device_id=None) | 将所有的模型参数和 buffers 复制到 CPU |
cuda(device_id=None) | 将所有的模型参数和 buffers 复制到 GPU。device_id 指定目标设备 |
double() | 将 parameters 和 buffers 的数据类型转换成 double |
eval() | 将模型设置成 evaluation 模式,仅当模型中有 Dropout 和 BatchNorm 时才会有影响 |
float() | 将 parameters 和 buffers 的数据类型转换成 float |
forward(*input) | 定义了每次执行的计算步骤,所有子类都需要重写这个函数 |
half() | 将 parameters 和 buffers 的数据类型转换成 half |
load_state_dict(state_dict) | 将 state_dict 中的 parameters 和 buffers 复制到此 module 和它的后代中,用来加载模型参数 |
modules() | 返回一个包含当前模型所有模块的迭代器 |
2. 卷积层
torch.nn.Conv1d
一维卷积层。
m = nn.Conv1d(16, 33, 3, stride=2)
input = autograd.Variable(torch.randn(20, 16, 50))
output = m(input)
| 参数 | 说明 |
|---|---|
in_channels (int) | 输入信号的通道 |
out_channels (int) | 卷积产生的通道 |
kernel_size (int or tuple) | 卷积核的尺寸 |
stride (int or tuple, optional) | 卷积步长 |
padding (int or tuple, optional) | 输入的每一条边补充 0 的层数 |
dilation (int or tuple, optional) | 卷积核元素之间的间距 |
groups (int, optional) | 从输入通道到输出通道的阻塞连接数 |
bias (bool, optional) | 如果 bias=True,添加偏置 |
torch.nn.Conv2d
二维卷积层。
# With square kernels and equal stride
m = nn.Conv2d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2))
# non-square kernels and unequal stride and with padding and dilation
m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1))
input = autograd.Variable(torch.randn(20, 16, 50, 100))
output = m(input)
| 参数 | 说明 |
|---|---|
in_channels (int) | 输入信号的通道 |
out_channels (int) | 卷积产生的通道 |
kernel_size (int or tuple) | 卷积核的尺寸 |
stride (int or tuple, optional) | 卷积步长 |
padding (int or tuple, optional) | 输入的每一条边补充 0 的层数 |
dilation (int or tuple, optional) | 卷积核元素之间的间距 |
groups (int, optional) | 从输入通道到输出通道的阻塞连接数 |
bias (bool, optional) | 如果 bias=True,添加偏置 |
torch.nn.Conv3d
三维卷积层。
# With square kernels and equal stride
m = nn.Conv3d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv3d(16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(4, 2, 0))
input = autograd.Variable(torch.randn(20, 16, 10, 50, 100))
output = m(input)
torch.nn.ConvTranspose1d
1 维的转置卷积操作(transposed convolution operator)。该操作可视作解卷积操作,但并不是真正的解卷积操作。可以看作是 Conv1d 相对于其输入的梯度。
| 参数 | 说明 |
|---|---|
in_channels (int) | 输入信号的通道数 |
out_channels (int) | 卷积产生的通道 |
kernel_size (int or tuple) | 卷积核的大小 |
stride (int or tuple, optional) | 卷积步长 |
padding (int or tuple, optional) | 输入的每一条边补充 0 的层数 |
output_padding (int or tuple, optional) | 输出的每一条边补充 0 的层数 |
dilation (int or tuple, optional) | 卷积核元素之间的间距 |
groups (int, optional) | 从输入通道到输出通道的阻塞连接数 |
bias (bool, optional) | 如果 bias=True,添加偏置 |
torch.nn.ConvTranspose2d
2 维的转置卷积操作。
# With square kernels and equal stride
m = nn.ConvTranspose2d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.ConvTranspose2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2))
input = autograd.Variable(torch.randn(20, 16, 50, 100))
output = m(input)
# exact output size can be also specified as an argument
input = autograd.Variable(torch.randn(1, 16, 12, 12))
downsample = nn.Conv2d(16, 16, 3, stride=2, padding=1)
upsample = nn.ConvTranspose2d(16, 16, 3, stride=2, padding=1)
h = downsample(input)
# h.size() -> torch.Size([1, 16, 6, 6])
output = upsample(h, output_size=input.size())
# output.size() -> torch.Size([1, 16, 12, 12])
torch.nn.ConvTranspose3d
3 维的转置卷积操作。
# With square kernels and equal stride
m = nn.ConvTranspose3d(16, 33, 3, stride=2)
# non-square kernels and unequal stride and with padding
m = nn.Conv3d(16, 33, (3, 5, 2), stride=(2, 1, 1), padding=(0, 4, 2))
input = autograd.Variable(torch.randn(20, 16, 10, 50, 100))
output = m(input)
3. 池化层
torch.nn.MaxPool1d
1 维最大池化(max pooling)。
# pool of size=3, stride=2
m = nn.MaxPool1d(3, stride=2)
input = autograd.Variable(torch.randn(20, 16, 50))
output = m(input)
| 参数 | 说明 |
|---|---|
kernel_size | max pooling 的窗口大小 |
stride | 窗口移动的步长,默认值是 kernel_size |
padding | 输入的每一条边补充 0 的层数 |
dilation | 控制窗口中元素步幅的参数 |
return_indices | 如果等于 True,返回输出最大值的序号,对 MaxUnpool1d 有用 |
ceil_mode | 如果等于 True,计算输出大小时使用向上取整 |
torch.nn.MaxPool2d
2 维最大池化。
# pool of square window of size=3, stride=2
m = nn.MaxPool2d(3, stride=2)
# pool of non-square window
m = nn.MaxPool2d((3, 2), stride=(2, 1))
input = autograd.Variable(torch.randn(20, 16, 50, 32))
output = m(input)
torch.nn.MaxPool3d
3 维最大池化。
# pool of square window of size=3, stride=2
m = nn.MaxPool3d(3, stride=2)
# pool of non-square window
m = nn.MaxPool3d((3, 2, 2), stride=(2, 1, 2))
input = autograd.Variable(torch.randn(20, 16, 50, 44, 31))
output = m(input)
torch.nn.MaxUnpool1d
MaxPool1d 的逆过程(非完全逆过程)。
pool = nn.MaxPool1d(2, stride=2, return_indices=True)
unpool = nn.MaxUnpool1d(2, stride=2)
input = Variable(torch.Tensor([[[1, 2, 3, 4, 5, 6, 7, 8]]]))
output, indices = pool(input)
unpool(output, indices)
# (0 ,.,.) = 0 2 0 4 0 6 0 8
# [torch.FloatTensor of size 1x1x8]
torch.nn.MaxUnpool2d
MaxPool2d 的逆过程。
pool = nn.MaxPool2d(2, stride=2, return_indices=True)
unpool = nn.MaxUnpool2d(2, stride=2)
input = Variable(torch.Tensor([[[[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9,10,11,12],
[13,14,15,16]]]]))
output, indices = pool(input)
unpool(output, indices)
# (0,0,.,.) =
# 0 0 0 0
# 0 6 0 8
# 0 0 0 0
# 0 14 0 16
# [torch.FloatTensor of size 1x1x4x4]
torch.nn.MaxUnpool3d
MaxPool3d 的逆过程。
pool = nn.MaxPool3d(3, stride=2, return_indices=True)
unpool = nn.MaxUnpool3d(3, stride=2)
output, indices = pool(Variable(torch.randn(20, 16, 51, 33, 15)))
unpooled_output = unpool(output, indices)
# unpooled_output.size() -> torch.Size([20, 16, 51, 33, 15])
torch.nn.AvgPool1d
1 维平均池化。
# pool with window of size=3, stride=2
m = nn.AvgPool1d(3, stride=2)
m(Variable(torch.Tensor([[[1, 2, 3, 4, 5, 6, 7]]])))
# (0,.,.) = 2 4 6
# [torch.FloatTensor of size 1x1x3]
| 参数 | 说明 |
|---|---|
kernel_size | 池化窗口大小 |
stride | 窗口移动的步长,默认值是 kernel_size |
padding | 输入的每一条边补充 0 的层数 |
ceil_mode | 如果等于 True,使用向上取整 |
count_include_pad | 如果等于 True,计算平均池化时将包括 padding 填充的 0 |
torch.nn.AvgPool2d
2 维的平均池化。
# pool of square window of size=3, stride=2
m = nn.AvgPool2d(3, stride=2)
# pool of non-square window
m = nn.AvgPool2d((3, 2), stride=(2, 1))
input = autograd.Variable(torch.randn(20, 16, 50, 32))
output = m(input)
torch.nn.AvgPool3d
3 维的平均池化。
# pool of square window of size=3, stride=2
m = nn.AvgPool3d(3, stride=2)
# pool of non-square window
m = nn.AvgPool3d((3, 2, 2), stride=(2, 1, 2))
input = autograd.Variable(torch.randn(20, 16, 50, 44, 31))
output = m(input)
torch.nn.FractionalMaxPool2d
2 维的分数最大化池化操作。
# pool of square window of size=3, and target output size 13x12
m = nn.FractionalMaxPool2d(3, output_size=(13, 12))
# pool of square window and target output size being half of input image size
m = nn.FractionalMaxPool2d(3, output_ratio=(0.5, 0.5))
input = autograd.Variable(torch.randn(20, 16, 50, 32))
output = m(input)
| 参数 | 说明 |
|---|---|
kernel_size | 最大池化操作时的窗口大小 |
output_size | 输出图像的尺寸,可用 tuple (oH, oW) 或数字 oH 指定 oH*oH |
output_ratio | 将输入图像大小百分比指定为输出图片大小,范围 (0, 1) |
return_indices | 默认 False,若 True 返回输出的索引 |
torch.nn.LPPool2d
2 维的幂平均池化操作。
# power-2 pool of square window of size=3, stride=2
m = nn.LPPool2d(2, 3, stride=2)
# pool of non-square window of power 1.2
m = nn.LPPool2d(1.2, (3, 2), stride=(2, 1))
input = autograd.Variable(torch.randn(20, 16, 50, 32))
output = m(input)
torch.nn.AdaptiveMaxPool1d
1 维的自适应最大池化操作。
# target output size of 5
m = nn.AdaptiveMaxPool1d(5)
input = autograd.Variable(torch.randn(1, 64, 8))
output = m(input)
torch.nn.AdaptiveMaxPool2d
2 维的自适应最大池化操作。
# target output size of 5x7
m = nn.AdaptiveMaxPool2d((5, 7))
input = autograd.Variable(torch.randn(1, 64, 8, 9))
# target output size of 7x7 (square)
m = nn.AdaptiveMaxPool2d(7)
input = autograd.Variable(torch.randn(1, 64, 10, 9))
output = m(input)
torch.nn.AdaptiveAvgPool1d
1 维的自适应平均池化操作。
# target output size of 5
m = nn.AdaptiveAvgPool1d(5)
input = autograd.Variable(torch.randn(1, 64, 8))
output = m(input)
torch.nn.AdaptiveAvgPool2d
2 维的自适应平均池化操作。
# target output size of 5x7
m = nn.AdaptiveAvgPool2d((5, 7))
input = autograd.Variable(torch.randn(1, 64, 8, 9))
# target output size of 7x7 (square)
m = nn.AdaptiveAvgPool2d(7)
input = autograd.Variable(torch.randn(1, 64, 10, 9))
output = m(input)
4. 激活函数
torch.nn.ReLU
ReLU(x) = max(0, x)。
m = nn.ReLU()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
参数:inplace — 选择是否进行覆盖运算。
torch.nn.ReLU6
ReLU6(x) = min(max(0, x), 6)。
m = nn.ReLU6()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.ELU
f(x) = max(0, x) + min(0, alpha * (e^x - 1))。
m = nn.ELU()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.PReLU
PReLU(x) = max(0, x) + a * min(0, x),a 是可学习参数。
m = nn.PReLU()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
| 参数 | 说明 |
|---|---|
num_parameters | 需要学习的 a 的个数,默认 1 |
init | a 的初始值,默认 0.25 |
torch.nn.LeakyReLU
f(x) = max(0, x) + negative_slope * min(0, x)。
m = nn.LeakyReLU(0.1)
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Threshold
y = x if x >= threshold;y = value if x < threshold。
m = nn.Threshold(0.1, 20)
input = Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Hardtanh
f(x) = +1 if x > 1;f(x) = -1 if x < -1;f(x) = x otherwise。
m = nn.Hardtanh()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Sigmoid
f(x) = 1 / (1 + e^{-x})。
m = nn.Sigmoid()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Tanh
f(x) = (e^x - e^{-x}) / (e^x + e^{-x})。
m = nn.Tanh()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.LogSigmoid
LogSigmoid(x) = log(1 / (1 + e^{-x}))。
m = nn.LogSigmoid()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Softplus
f(x) = (1/beta) * log(1 + e^(beta * x_i)),ReLU 的平滑逼近。
m = nn.Softplus()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Softshrink
f(x) = x - lambda if x > lambda;f(x) = x + lambda if x < -lambda;f(x) = 0 otherwise。
m = nn.Softshrink()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Softsign
f(x) = x / (1 + |x|)。
m = nn.Softsign()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Tanhshrink
Tanhshrink(x) = x - Tanh(x)。
m = nn.Tanhshrink()
input = autograd.Variable(torch.randn(2))
print(input)
print(m(input))
torch.nn.Softmin
将张量的每个元素缩放到 (0, 1) 区间且和为 1。
m = nn.Softmin()
input = autograd.Variable(torch.randn(2, 3))
print(input)
print(m(input))
torch.nn.Softmax
m = nn.Softmax()
input = autograd.Variable(torch.randn(2, 3))
print(input)
print(m(input))
torch.nn.LogSoftmax
m = nn.LogSoftmax()
input = autograd.Variable(torch.randn(2, 3))
print(input)
print(m(input))
5. 标准化层
torch.nn.BatchNorm1d
对小批量 2d 或 3d 输入进行批标准化。
# With Learnable Parameters
m = nn.BatchNorm1d(100)
# Without Learnable Parameters
m = nn.BatchNorm1d(100, affine=False)
input = autograd.Variable(torch.randn(20, 100))
output = m(input)
| 参数 | 说明 |
|---|---|
num_features | 期望输入的特征数,大小为 batch_size x num_features [x width] |
eps | 为保证数值稳定性给分母加上的值,默认 1e-5 |
momentum | 动态均值和动态方差所使用的动量,默认 0.1 |
affine | 当设为 True,给该层添加可学习的仿射变换参数 |
torch.nn.BatchNorm2d
对小批量 3d 数据组成的 4d 输入进行批标准化。
# With Learnable Parameters
m = nn.BatchNorm2d(100)
# Without Learnable Parameters
m = nn.BatchNorm2d(100, affine=False)
input = autograd.Variable(torch.randn(20, 100, 35, 45))
output = m(input)
torch.nn.BatchNorm3d
对小批量 4d 数据组成的 5d 输入进行批标准化。
# With Learnable Parameters
m = nn.BatchNorm3d(100)
# Without Learnable Parameters
m = nn.BatchNorm3d(100, affine=False)
input = autograd.Variable(torch.randn(20, 100, 35, 45, 10))
output = m(input)
6. 递归层
torch.nn.RNN
多层 Elman RNN,激活函数为 tanh 或 ReLU。
rnn = nn.RNN(10, 20, 2)
input = Variable(torch.randn(5, 3, 10))
h0 = Variable(torch.randn(2, 3, 20))
output, hn = rnn(input, h0)
| 参数 | 说明 |
|---|---|
input_size | 输入 x 的特征数量 |
hidden_size | 隐层的特征数量 |
num_layers | RNN 的层数 |
nonlinearity | 指定非线性函数:tanh 或 relu,默认 tanh |
bias | False 则不使用偏置权重,默认 True |
batch_first | True 时 input Tensor shape 为 [batch_size, time_step, feature] |
dropout | 非零时,除最后一层外其他层输出会套上 dropout |
bidirectional | True 则变成双向 RNN,默认 False |
torch.nn.LSTM
多层 LSTM。
lstm = nn.LSTM(10, 20, 2)
input = Variable(torch.randn(5, 3, 10))
h0 = Variable(torch.randn(2, 3, 20))
c0 = Variable(torch.randn(2, 3, 20))
output, hn = lstm(input, (h0, c0))
| 参数 | 说明 |
|---|---|
input_size | 输入的特征维度 |
hidden_size | 隐状态的特征维度 |
num_layers | 层数 |
bias | False 则不使用 bias,默认 True |
batch_first | True 时 shape 为 (batch, seq, feature) |
dropout | 非零时加 dropout(最后一层除外) |
bidirectional | True 则变成双向 RNN,默认 False |
torch.nn.GRU
多层 GRU。
rnn = nn.GRU(10, 20, 2)
input = Variable(torch.randn(5, 3, 10))
h0 = Variable(torch.randn(2, 3, 20))
output, hn = rnn(input, h0)
torch.nn.RNNCell
Elman RNN cell。
rnn = nn.RNNCell(10, 20)
input = Variable(torch.randn(6, 3, 10))
hx = Variable(torch.randn(3, 20))
output = []
for i in range(6):
hx = rnn(input[i], hx)
output.append(hx)
torch.nn.LSTMCell
LSTM cell。
rnn = nn.LSTMCell(10, 20)
input = Variable(torch.randn(6, 3, 10))
hx = Variable(torch.randn(3, 20))
cx = Variable(torch.randn(3, 20))
output = []
for i in range(6):
hx, cx = rnn(input[i], (hx, cx))
output.append(hx)
torch.nn.GRUCell
GRU cell。
rnn = nn.GRUCell(10, 20)
input = Variable(torch.randn(6, 3, 10))
hx = Variable(torch.randn(3, 20))
output = []
for i in range(6):
hx = rnn(input[i], hx)
output.append(hx)
7. 线性层
torch.nn.Linear
对输入数据做线性变换:y = Ax + b。
m = nn.Linear(20, 30)
input = autograd.Variable(torch.randn(128, 20))
output = m(input)
print(output.size())
| 参数 | 说明 |
|---|---|
in_features | 每个输入样本的大小 |
out_features | 每个输出样本的大小 |
bias | 若 False,不学习偏置,默认 True |
8. Dropout 层
torch.nn.Dropout
随机将输入张量中部分元素设置为 0。
m = nn.Dropout(p=0.2)
input = autograd.Variable(torch.randn(20, 16))
output = m(input)
| 参数 | 说明 |
|---|---|
p | 将元素置 0 的概率,默认 0.5 |
inplace | 若 True,在原地执行操作,默认 False |
torch.nn.Dropout2d
随机将输入张量中整个通道设置为 0。
m = nn.Dropout2d(p=0.2)
input = autograd.Variable(torch.randn(20, 16, 32, 32))
output = m(input)
torch.nn.Dropout3d
随机将输入张量中整个通道设置为 0。
m = nn.Dropout3d(p=0.2)
input = autograd.Variable(torch.randn(20, 16, 4, 32, 32))
output = m(input)
9. Sparse 层
torch.nn.Embedding
保存固定字典和大小的简单查找表,常用来保存词嵌入和用下标检索。
# an Embedding module containing 10 tensors of size 3
embedding = nn.Embedding(10, 3)
# a batch of 2 samples of 4 indices each
input = Variable(torch.LongTensor([[1, 2, 4, 5], [4, 3, 2, 9]]))
embedding(input)
# [torch.FloatTensor of size 2x4x3]
# example with padding_idx
embedding = nn.Embedding(10, 3, padding_idx=0)
input = Variable(torch.LongTensor([[0, 2, 0, 5]]))
embedding(input)
# [torch.FloatTensor of size 1x4x3] — padding_idx=0 的位置输出全 0
| 参数 | 说明 |
|---|---|
num_embeddings (int) | 嵌入字典的大小 |
embedding_dim (int) | 每个嵌入向量的大小 |
padding_idx (int, optional) | 如果提供,输出遇到此下标时用零填充 |
max_norm (float, optional) | 如果提供,重新归一化词嵌入使范数小于提供的值 |
norm_type (float, optional) | 对于 max_norm 计算 p 范数时的 p |
scale_grad_by_freq (boolean, optional) | 如果提供,根据字典中单词频率缩放梯度 |
10. 距离计算层
torch.nn.PairwiseDistance
按批计算向量 v1、v2 之间的距离。
pdist = nn.PairwiseDistance(2)
input1 = autograd.Variable(torch.randn(100, 128))
input2 = autograd.Variable(torch.randn(100, 128))
output = pdist(input1, input2)
| 参数 | 说明 |
|---|---|
x (Tensor) | 包含两个输入 batch 的张量 |
p (real) | 范数次数,默认 2 |
11. 损失函数
基本用法
criterion = LossCriterion() # 构造函数有自己的参数
loss = criterion(x, y) # 调用标准时也有参数
常用损失函数
| 函数 | 说明 |
|---|---|
torch.nn.L1Loss | 衡量输入 x 和目标 y 之间差的绝对值的平均值 |
torch.nn.MSELoss | 衡量输入 x 和目标 y 之间均方误差 |
torch.nn.CrossEntropyLoss | 将 LogSoftMax 和 NLLLoss 集成到一个类中 |
torch.nn.NLLLoss | 负的 log likelihood loss,用于训练 n 类分类器 |
torch.nn.NLLLoss2d | 对于图片的 negative log likelihood loss,计算每个像素的 NLL loss |
torch.nn.KLDivLoss | 计算 KL 散度损失 |
torch.nn.BCELoss | 计算 target 与 output 之间的二进制交叉熵 |
torch.nn.MarginRankingLoss | 给定 x1、x2 两个 1-D Tensor 和标签 y(值为 -1 或 1) |
torch.nn.HingeEmbeddingLoss | 给定输入 x 和标签 y(1 或 -1)计算损失值 |
torch.nn.MultiLabelMarginLoss | 计算多标签分类的 hinge loss(margin-based loss) |
torch.nn.SmoothL1Loss | 平滑版 L1 loss |
torch.nn.SoftMarginLoss | 优化 2 分类的 logistic loss |
torch.nn.MultiLabelSoftMarginLoss | 基于 max-entropy 优化多标签 one-versus-all 的损失 |
torch.nn.CosineEmbeddingLoss | 使用 cosine 距离测量两个输入是否相似,用于学习非线性 embedding 或半监督学习 |
torch.nn.MultiMarginLoss | 计算 multi-class classification 的 hinge loss(margin-based loss) |
torch.nn.NLLLoss 示例
m = nn.LogSoftmax()
loss = nn.NLLLoss()
# input is of size nBatch x nClasses = 3 x 5
input = autograd.Variable(torch.randn(3, 5), requires_grad=True)
# each element in target has to have 0 <= value < nclasses
target = autograd.Variable(torch.LongTensor([1, 0, 4]))
output = loss(m(input), target)
output.backward()
其他损失函数详解
torch.nn.KLDivLoss(weight=None, size_average=True)
计算 KL 散度损失。
torch.nn.BCELoss(weight=None, size_average=True)
计算 target 与 output 之间的二进制交叉熵。
torch.nn.MarginRankingLoss(margin=0, size_average=True)
创建一个标准,给定输入 x1、x2 两个 1-D Tensor,和一个标签 y(1-D mini-batch tensor),y 里面的值只能是 -1 或 1。
torch.nn.HingeEmbeddingLoss(size_average=True)
给定一个输入 $x$(2-D mini-batch tensor)和对应的标签 $y$(1-D tensor,值为 1 或 -1),此函数用来计算之间的损失值。
torch.nn.MultiLabelMarginLoss(size_average=True)
计算多标签分类的 hinge loss(margin-based loss),计算 loss 时需要两个输入:
- input $x$:2-D mini-batch Tensor
- output $y$:2-D Tensor,表示 mini-batch 中样本类别的索引
torch.nn.SmoothL1Loss(size_average=True)
平滑版 L1 loss。
torch.nn.SoftMarginLoss(size_average=True)
创建一个标准,用来优化 2 分类的 logistic loss。输入为 $x$(一个 2-D mini-batch Tensor)和目标 $y$(一个包含 1 或 -1 的 Tensor)。
torch.nn.MultiLabelSoftMarginLoss(weight=None, size_average=True)
创建一个标准,基于输入 $x$ 和目标 $y$ 的 max-entropy,优化多标签 one-versus-all 的损失。
torch.nn.CosineEmbeddingLoss(margin=0, size_average=True)
给定输入 Tensors x1、x2 和一个标签 Tensor $y$(元素的值为 1 或 -1)。此标准使用 cosine 距离测量两个输入是否相似,一般用来学习非线性 embedding 或者半监督学习。
torch.nn.MultiMarginLoss(p=1, margin=1, weight=None, size_average=True)
用来计算 multi-class classification 的 hinge loss(margin-based loss)。
12. 图像处理层
torch.nn.PixelShuffle(upscale_factor)
将 shape 为 [N, C*r^2, H, W] 的 Tensor 重新排列为 shape 为 [N, C, H*r, W*r] 的 Tensor。
参数说明:
upscale_factor(int) – 增加空间分辨率的因子
示例:
ps = nn.PixelShuffle(3)
input = autograd.Variable(torch.Tensor(1, 9, 4, 4))
output = ps(input)
print(output.size())
# torch.Size([1, 1, 12, 12])
torch.nn.UpsamplingNearest2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D 最近邻上采样。
参数说明:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingNearest2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1 1 2 2
# 1 1 2 2
# 3 3 4 4
# 3 3 4 4
# [torch.FloatTensor of size 1x1x4x4]
torch.nn.UpsamplingBilinear2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D bilinear 上采样。
参数:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingBilinear2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1.0000 1.3333 1.6667 2.0000
# 1.6667 2.0000 2.3333 2.6667
# 2.3333 2.6667 3.0000 3.3333
# 3.0000 3.3333 3.6667 4.0000
# [torch.FloatTensor of size 1x1x4x4]
13. 多 GPU 并行
torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0)
在模块级别上实现数据并行。
参数说明:
module– 要被并行的 moduledevice_ids– CUDA 设备,默认为所有设备output_device– 输出设备(默认为device_ids[0])
示例:
net = torch.nn.DataParallel(model, device_ids=[0, 1, 2])
output = net(input_var)
14. 工具函数
torch.nn.utils.clip_grad_norm(parameters, max_norm, norm_type=2)
正则项的值由所有的梯度计算出来,就像他们连成一个向量一样。梯度被 in-place operation 修改。
参数说明:
parameters(Iterable[Variable]) – 可迭代的 Variables,它们的梯度即将被标准化max_norm(float or int) – clip 后,gradients p-norm 值norm_type(float or int) – 标准化的类型,p-norm,可以是inf代表 infinity norm
torch.nn.utils.pad_sequence(sequences, batch_first=True, padding_value=0)
将一个列表中的多个序列(如多个一维张量)填充为具有相同长度的二维张量。
参数说明:
sequences– 一个包含多个一维张量的列表,每个张量代表一个序列batch_first– 布尔值,指示返回的张量是否以批处理维度作为第一个维度(True)还是以序列长度作为第一个维度(False)。默认为Falsepadding_value– 用于填充的值,默认为0
torch.nn.utils.rnn.PackedSequence(_cls, data, batch_sizes)
所有的 RNN 模块都接收这种被包裹后的序列作为它们的输入。
参数说明:
data(Variable) – 包含打包后序列的 Variablebatch_sizes(list[int]) – 包含 mini-batch 中每个序列长度的列表
torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_first=False)
将一个填充过的变长序列压紧。
参数说明:
input(Variable) – 变长序列被填充后的 batchlengths(list[int]) – Variable 中每个序列的长度batch_first(bool, optional) – 如果是True,input 的形状应该是B*T*size
torch.nn.utils.rnn.pad_packed_sequence(sequence, batch_first=False)
和 pack_padded_sequence() 相反。把压紧的序列再填充回来。
参数说明:
sequence(PackedSequence) – 将要被填充的 batchbatch_first(bool, optional) – 如果为True,返回的数据的格式为B×T×*
示例:
import torch
import torch.nn as nn
from torch.autograd import Variable
from torch.nn import utils as nn_utils
batch_size = 2
max_length = 3
hidden_size = 2
n_layers = 1
tensor_in = torch.FloatTensor([[1, 2, 3], [1, 0, 0]]).resize_(2, 3, 1)
tensor_in = Variable(tensor_in) # [batch, seq, feature], [2, 3, 1]
seq_lengths = [3, 1] # list of integers holding information about the batch size at each sequence step
# pack it
pack = nn_utils.rnn.pack_padded_sequence(tensor_in, seq_lengths, batch_first=True)
# initialize
rnn = nn.RNN(1, hidden_size, n_layers, batch_first=True)
h0 = Variable(torch.randn(n_layers, batch_size, hidden_size))
# forward
out, _ = rnn(pack, h0)
# unpack
unpacked = nn_utils.rnn.pad_packed_sequence(out)
print(unpacked)
torch.utils.data.Dataset
表示 Dataset 的抽象类。所有其他数据集都应该进行子类化。所有子类应该覆写 __len__ 和 __getitem__,前者提供了数据集的大小,后者支持整数索引,范围从 0 到 len(self)。
torch.utils.data.TensorDataset(data_tensor, target_tensor)
包装数据和目标张量的数据集。通过沿着第一个维度索引两个张量来恢复每个样本。
参数:
data_tensor(Tensor) – 包含样本数据target_tensor(Tensor) – 包含样本目标(标签)
torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=<function default_collate>, pin_memory=False, drop_last=False)
数据加载器。组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。
参数:
dataset(Dataset) – 加载数据的数据集batch_size(int, optional) – 每个 batch 加载多少个样本(默认:1)shuffle(bool, optional) – 设置为True时会在每个 epoch 重新打乱数据(默认:False)sampler(Sampler, optional) – 定义从数据集中提取样本的策略。如果指定,则忽略shuffle参数num_workers(int, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认:0)collate_fn(callable, optional) – 将样本合并成 batch 的函数pin_memory(bool, optional) – 是否将数据拷贝到 CUDA 固定内存drop_last(bool, optional) – 如果数据集大小不能被 batch size 整除,则设置为True后可删除最后一个不完整的 batch。如果设为False并且数据集的大小不能被 batch size 整除,则最后一个 batch 将更小(默认:False)
torch.utils.data.sampler.Sampler(data_source)
所有采样器的基础类。每个采样器子类必须提供一个 __iter__ 方法,提供一种迭代数据集元素的索引的方法,以及返回迭代器长度的 __len__ 方法。
torch.utils.data.sampler.SequentialSampler(data_source)
样本元素顺序排列,始终以相同的顺序。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.RandomSampler(data_source)
样本元素随机,没有替换。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.SubsetRandomSampler(indices)
样本元素从指定的索引列表中随机抽取,没有替换。
参数:
indices(list) – 索引的列表
torch.utils.data.sampler.WeightedRandomSampler(weights, num_samples, replacement=True)
样本元素来自于 [0, ..., len(weights)-1],给定概率(weights)。
参数:
weights(list) – 权重列表,没必要加起来为1num_samples(int) – 抽样数量
15. Convolution 卷积层函数式接口
torch.nn.functional.conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 1D 卷积。
参数说明:
input– 输入张量的形状(minibatch x in_channels x iW)weight– 过滤器的形状(out_channels, in_channels, kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,默认为1
示例:
filters = autograd.Variable(torch.randn(33, 16, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50))
F.conv1d(inputs, filters)
torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 2D 卷积。
参数:
input– 输入张量(minibatch x in_channels x iH x iW)weight– 过滤器张量(out_channels, in_channels/groups, kH, kW)bias– 可选偏置张量(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0groups– 将输入分成组,in_channels应该被组数除尽
示例:
# With square kernels and equal stride
filters = autograd.Variable(torch.randn(8, 4, 3, 3))
inputs = autograd.Variable(torch.randn(1, 4, 5, 5))
F.conv2d(inputs, filters, padding=1)
torch.nn.functional.conv3d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 3D 卷积。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器张量的形状(out_channels, in_channels, kT, kH, kW)bias– 可选偏置张量的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0
示例:
filters = autograd.Variable(torch.randn(33, 16, 3, 3, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50, 10, 20))
F.conv3d(inputs, filters)
torch.nn.functional.conv_transpose1d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用一维转置卷积,有时也称为”去卷积”。
torch.nn.functional.conv_transpose2d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用二维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0groups– 将输入分成组,in_channels应该被组数除尽output_padding–0 <= padding < stride的零填充,应该添加到输出。可以是单个数字或元组。默认值:0
torch.nn.functional.conv_transpose3d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用三维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0
16. Pooling 池化层函数式接口
torch.nn.functional.avg_pool1d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
对由几个输入平面组成的输入信号进行一维平均池化。
参数:
kernel_size– 窗口的大小stride– 窗口的步长。默认值为kernel_sizepadding– 在两边添加隐式零填充ceil_mode– 当为True时,将使用ceil代替floor来计算输出形状count_include_pad– 当为True时,这将在平均计算时包括补零
示例:
# pool of square window of size=3, stride=2
input = Variable(torch.Tensor([[[1, 2, 3, 4, 5, 6, 7]]]))
F.avg_pool1d(input, kernel_size=3, stride=2)
# Variable containing:
# (0 ,.,.) =
# 2 4 6
# [torch.FloatTensor of size 1x1x3]
torch.nn.functional.avg_pool2d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
在 kh x kw 区域中应用步长为 dh x dw 的二维平均池化操作。输出特征的数量等于输入平面的数量。
参数:
input– 输入的张量(minibatch x in_channels x iH x iW)kernel_size– 池化区域的大小,可以是单个数字或者元组(kh x kw)stride– 池化操作的步长,可以是单个数字或者元组(sh x sw)。默认等于核的大小padding– 在输入上隐式的零填充,可以是单个数字或者一个元组(padh x padw),默认:0ceil_mode– 定义空间输出形状的操作count_include_pad– 除以原始非填充图像内的元素数量或kh * kw
torch.nn.functional.avg_pool3d(input, kernel_size, stride=None)
在 kt x kh x kw 区域中应用步长为 dt x dh x dw 的三维平均池化操作。输出特征的数量等于 input planes / dt。
torch.nn.functional.max_pool1d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行一维最大池化。
torch.nn.functional.max_pool2d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行二维最大池化。
torch.nn.functional.max_pool3d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行三维最大池化。
torch.nn.functional.max_unpool1d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
一维最大池化逆操作。
torch.nn.functional.max_unpool2d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
二维最大池化逆操作。
torch.nn.functional.max_unpool3d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
三维最大池化逆操作。
torch.nn.functional.lp_pool2d(input, norm_type, kernel_size, stride=None, ceil_mode=False)
二维 Lp 池化操作。
torch.nn.functional.adaptive_max_pool1d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 1D 自适应最大池化。
参数:
output_size– 目标输出大小(单个整数)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_max_pool2d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 2D 自适应最大池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_avg_pool1d(input, output_size)
在由几个输入平面组成的输入信号上应用 1D 自适应平均池化。
参数:
output_size– 目标输出大小(单个整数)
torch.nn.functional.adaptive_avg_pool2d(input, output_size)
在由几个输入平面组成的输入信号上应用 2D 自适应平均池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)
17. 激活函数 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.threshold(input, threshold, value, inplace=False) | 阈值激活函数 |
torch.nn.functional.relu(input, inplace=False) | ReLU 激活函数 |
torch.nn.functional.hardtanh(input, min_val=-1., max_val=1., inplace=False) | HardTanh 激活函数 |
torch.nn.functional.relu6(input, inplace=False) | ReLU6 激活函数 |
torch.nn.functional.elu(input, alpha=1.0, inplace=False) | ELU 激活函数 |
torch.nn.functional.leaky_relu(input, negative_slope=0.01, inplace=False) | Leaky ReLU 激活函数 |
torch.nn.functional.prelu(input, weight) | PReLU 激活函数 |
torch.nn.functional.rrelu(input, lower=0.125, upper=0.3333333333333333, training=False, inplace=False) | RReLU 激活函数 |
torch.nn.functional.logsigmoid(input) | LogSigmoid 激活函数 |
torch.nn.functional.hardshrink(input, lambd=0.5) | HardShrink 激活函数 |
torch.nn.functional.tanhshrink(input) | TanhShrink 激活函数 |
torch.nn.functional.softsign(input) | SoftSign 激活函数 |
torch.nn.functional.softplus(input, beta=1, threshold=20) | Softplus 激活函数 |
torch.nn.functional.softmin(input) | Softmin 激活函数 |
torch.nn.functional.softmax(input) | Softmax 激活函数 |
torch.nn.functional.softshrink(input, lambd=0.5) | Softshrink 激活函数 |
torch.nn.functional.log_softmax(input) | LogSoftmax 激活函数 |
torch.nn.functional.tanh(input) | Tanh 激活函数 |
torch.nn.functional.sigmoid(input) | Sigmoid 激活函数 |
18. Normalization 标准化 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.batch_norm(input, running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-05) | 批量归一化 |
torch.nn.functional.normalize(input, p=2.0, dim=1, eps=1e-12, out=None) | Lp 归一化 |
19. 线性函数 函数式接口
torch.nn.functional.linear(input, weight, bias=None)
对输入进行线性变换:$y = xA^T + b$。
20. Dropout 函数式接口
torch.nn.functional.dropout(input, p=0.5, training=False, inplace=False)
在训练期间,以概率 p 随机将输入张量的某些元素置零。
21. 距离函数 函数式接口
torch.nn.functional.pairwise_distance(x1, x2, p=2, eps=1e-06)
计算两个输入张量之间的成对距离(p-norm)。
参数:
x1– 第一个输入的张量x2– 第二个输入的张量p– 矩阵范数的维度。默认值是2,即二范数
示例:
input1 = autograd.Variable(torch.randn(100, 128))
input2 = autograd.Variable(torch.randn(100, 128))
output = F.pairwise_distance(input1, input2, p=2)
output.backward()
22. 损失函数 函数式接口
torch.nn.functional.nll_loss(input, target, weight=None, size_average=True)
负的 log likelihood 损失函数。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.kl_div(input, target, size_average=True)
KL 散度损失函数。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variablesize_average– 如果为True,loss 则是平均值,需要除以输入 tensor 中 element 的数目
torch.nn.functional.cross_entropy(input, target, weight=None, size_average=True)
该函数使用了 log_softmax 和 nll_loss。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.binary_cross_entropy(input, target, weight=None, size_average=True)
该函数计算了输出与 target 之间的二进制交叉熵。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variableweight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.smooth_l1_loss(input, target, size_average=True)
平滑版 L1 loss。如果绝对误差低于 1,则使用平方项,否则使用 L1 项。
torch.nn.NLLLoss2d 示例
m = nn.Conv2d(16, 32, (3, 3)).float()
loss = nn.NLLLoss2d()
# input is of size nBatch x nClasses x height x width
input = autograd.Variable(torch.randn(3, 16, 10, 10))
# each element in target has to have 0 <= value < nclasses
target = autograd.Variable(torch.LongTensor(3, 8, 8).random_(0, 4))
output = loss(m(input), target)
output.backward()
其他损失函数详解
torch.nn.KLDivLoss(weight=None, size_average=True)
计算 KL 散度损失。
torch.nn.BCELoss(weight=None, size_average=True)
计算 target 与 output 之间的二进制交叉熵。
torch.nn.MarginRankingLoss(margin=0, size_average=True)
创建一个标准,给定输入 x1、x2 两个 1-D Tensor,和一个标签 y(1-D mini-batch tensor),y 里面的值只能是 -1 或 1。
torch.nn.HingeEmbeddingLoss(size_average=True)
给定一个输入 $x$(2-D mini-batch tensor)和对应的标签 $y$(1-D tensor,值为 1 或 -1),此函数用来计算之间的损失值。
torch.nn.MultiLabelMarginLoss(size_average=True)
计算多标签分类的 hinge loss(margin-based loss),计算 loss 时需要两个输入:
- input $x$:2-D mini-batch Tensor
- output $y$:2-D Tensor,表示 mini-batch 中样本类别的索引
torch.nn.SmoothL1Loss(size_average=True)
平滑版 L1 loss。
torch.nn.SoftMarginLoss(size_average=True)
创建一个标准,用来优化 2 分类的 logistic loss。输入为 $x$(一个 2-D mini-batch Tensor)和目标 $y$(一个包含 1 或 -1 的 Tensor)。
torch.nn.MultiLabelSoftMarginLoss(weight=None, size_average=True)
创建一个标准,基于输入 $x$ 和目标 $y$ 的 max-entropy,优化多标签 one-versus-all 的损失。
torch.nn.CosineEmbeddingLoss(margin=0, size_average=True)
给定输入 Tensors x1、x2 和一个标签 Tensor $y$(元素的值为 1 或 -1)。此标准使用 cosine 距离测量两个输入是否相似,一般用来学习非线性 embedding 或者半监督学习。
torch.nn.MultiMarginLoss(p=1, margin=1, weight=None, size_average=True)
用来计算 multi-class classification 的 hinge loss(margin-based loss)。
12. 图像处理层
torch.nn.PixelShuffle(upscale_factor)
将 shape 为 [N, C*r^2, H, W] 的 Tensor 重新排列为 shape 为 [N, C, H*r, W*r] 的 Tensor。
参数说明:
upscale_factor(int) – 增加空间分辨率的因子
示例:
ps = nn.PixelShuffle(3)
input = autograd.Variable(torch.Tensor(1, 9, 4, 4))
output = ps(input)
print(output.size())
# torch.Size([1, 1, 12, 12])
torch.nn.UpsamplingNearest2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D 最近邻上采样。
参数说明:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingNearest2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1 1 2 2
# 1 1 2 2
# 3 3 4 4
# 3 3 4 4
# [torch.FloatTensor of size 1x1x4x4]
torch.nn.UpsamplingBilinear2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D bilinear 上采样。
参数:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingBilinear2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1.0000 1.3333 1.6667 2.0000
# 1.6667 2.0000 2.3333 2.6667
# 2.3333 2.6667 3.0000 3.3333
# 3.0000 3.3333 3.6667 4.0000
# [torch.FloatTensor of size 1x1x4x4]
13. 多 GPU 并行
torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0)
在模块级别上实现数据并行。
参数说明:
module– 要被并行的 moduledevice_ids– CUDA 设备,默认为所有设备output_device– 输出设备(默认为device_ids[0])
示例:
net = torch.nn.DataParallel(model, device_ids=[0, 1, 2])
output = net(input_var)
14. 工具函数
torch.nn.utils.clip_grad_norm(parameters, max_norm, norm_type=2)
正则项的值由所有的梯度计算出来,就像他们连成一个向量一样。梯度被 in-place operation 修改。
参数说明:
parameters(Iterable[Variable]) – 可迭代的 Variables,它们的梯度即将被标准化max_norm(float or int) – clip 后,gradients p-norm 值norm_type(float or int) – 标准化的类型,p-norm,可以是inf代表 infinity norm
torch.nn.utils.pad_sequence(sequences, batch_first=True, padding_value=0)
将一个列表中的多个序列(如多个一维张量)填充为具有相同长度的二维张量。
参数说明:
sequences– 一个包含多个一维张量的列表,每个张量代表一个序列batch_first– 布尔值,指示返回的张量是否以批处理维度作为第一个维度(True)还是以序列长度作为第一个维度(False)。默认为Falsepadding_value– 用于填充的值,默认为0
torch.nn.utils.rnn.PackedSequence(_cls, data, batch_sizes)
所有的 RNN 模块都接收这种被包裹后的序列作为它们的输入。
参数说明:
data(Variable) – 包含打包后序列的 Variablebatch_sizes(list[int]) – 包含 mini-batch 中每个序列长度的列表
torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_first=False)
将一个填充过的变长序列压紧。
参数说明:
input(Variable) – 变长序列被填充后的 batchlengths(list[int]) – Variable 中每个序列的长度batch_first(bool, optional) – 如果是True,input 的形状应该是B*T*size
torch.nn.utils.rnn.pad_packed_sequence(sequence, batch_first=False)
和 pack_padded_sequence() 相反。把压紧的序列再填充回来。
参数说明:
sequence(PackedSequence) – 将要被填充的 batchbatch_first(bool, optional) – 如果为True,返回的数据的格式为B×T×*
示例:
import torch
import torch.nn as nn
from torch.autograd import Variable
from torch.nn import utils as nn_utils
batch_size = 2
max_length = 3
hidden_size = 2
n_layers = 1
tensor_in = torch.FloatTensor([[1, 2, 3], [1, 0, 0]]).resize_(2, 3, 1)
tensor_in = Variable(tensor_in) # [batch, seq, feature], [2, 3, 1]
seq_lengths = [3, 1] # list of integers holding information about the batch size at each sequence step
# pack it
pack = nn_utils.rnn.pack_padded_sequence(tensor_in, seq_lengths, batch_first=True)
# initialize
rnn = nn.RNN(1, hidden_size, n_layers, batch_first=True)
h0 = Variable(torch.randn(n_layers, batch_size, hidden_size))
# forward
out, _ = rnn(pack, h0)
# unpack
unpacked = nn_utils.rnn.pad_packed_sequence(out)
print(unpacked)
torch.utils.data.Dataset
表示 Dataset 的抽象类。所有其他数据集都应该进行子类化。所有子类应该覆写 __len__ 和 __getitem__,前者提供了数据集的大小,后者支持整数索引,范围从 0 到 len(self)。
torch.utils.data.TensorDataset(data_tensor, target_tensor)
包装数据和目标张量的数据集。通过沿着第一个维度索引两个张量来恢复每个样本。
参数:
data_tensor(Tensor) – 包含样本数据target_tensor(Tensor) – 包含样本目标(标签)
torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=<function default_collate>, pin_memory=False, drop_last=False)
数据加载器。组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。
参数:
dataset(Dataset) – 加载数据的数据集batch_size(int, optional) – 每个 batch 加载多少个样本(默认:1)shuffle(bool, optional) – 设置为True时会在每个 epoch 重新打乱数据(默认:False)sampler(Sampler, optional) – 定义从数据集中提取样本的策略。如果指定,则忽略shuffle参数num_workers(int, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认:0)collate_fn(callable, optional) – 将样本合并成 batch 的函数pin_memory(bool, optional) – 是否将数据拷贝到 CUDA 固定内存drop_last(bool, optional) – 如果数据集大小不能被 batch size 整除,则设置为True后可删除最后一个不完整的 batch。如果设为False并且数据集的大小不能被 batch size 整除,则最后一个 batch 将更小(默认:False)
torch.utils.data.sampler.Sampler(data_source)
所有采样器的基础类。每个采样器子类必须提供一个 __iter__ 方法,提供一种迭代数据集元素的索引的方法,以及返回迭代器长度的 __len__ 方法。
torch.utils.data.sampler.SequentialSampler(data_source)
样本元素顺序排列,始终以相同的顺序。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.RandomSampler(data_source)
样本元素随机,没有替换。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.SubsetRandomSampler(indices)
样本元素从指定的索引列表中随机抽取,没有替换。
参数:
indices(list) – 索引的列表
torch.utils.data.sampler.WeightedRandomSampler(weights, num_samples, replacement=True)
样本元素来自于 [0, ..., len(weights)-1],给定概率(weights)。
参数:
weights(list) – 权重列表,没必要加起来为1num_samples(int) – 抽样数量
15. Convolution 卷积层函数式接口
torch.nn.functional.conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 1D 卷积。
参数说明:
input– 输入张量的形状(minibatch x in_channels x iW)weight– 过滤器的形状(out_channels, in_channels, kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,默认为1
示例:
filters = autograd.Variable(torch.randn(33, 16, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50))
F.conv1d(inputs, filters)
torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 2D 卷积。
参数:
input– 输入张量(minibatch x in_channels x iH x iW)weight– 过滤器张量(out_channels, in_channels/groups, kH, kW)bias– 可选偏置张量(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0groups– 将输入分成组,in_channels应该被组数除尽
示例:
# With square kernels and equal stride
filters = autograd.Variable(torch.randn(8, 4, 3, 3))
inputs = autograd.Variable(torch.randn(1, 4, 5, 5))
F.conv2d(inputs, filters, padding=1)
torch.nn.functional.conv3d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 3D 卷积。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器张量的形状(out_channels, in_channels, kT, kH, kW)bias– 可选偏置张量的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0
示例:
filters = autograd.Variable(torch.randn(33, 16, 3, 3, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50, 10, 20))
F.conv3d(inputs, filters)
torch.nn.functional.conv_transpose1d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用一维转置卷积,有时也称为”去卷积”。
torch.nn.functional.conv_transpose2d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用二维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0groups– 将输入分成组,in_channels应该被组数除尽output_padding–0 <= padding < stride的零填充,应该添加到输出。可以是单个数字或元组。默认值:0
torch.nn.functional.conv_transpose3d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用三维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0
16. Pooling 池化层函数式接口
torch.nn.functional.avg_pool1d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
对由几个输入平面组成的输入信号进行一维平均池化。
参数:
kernel_size– 窗口的大小stride– 窗口的步长。默认值为kernel_sizepadding– 在两边添加隐式零填充ceil_mode– 当为True时,将使用ceil代替floor来计算输出形状count_include_pad– 当为True时,这将在平均计算时包括补零
示例:
# pool of square window of size=3, stride=2
input = Variable(torch.Tensor([[[1, 2, 3, 4, 5, 6, 7]]]))
F.avg_pool1d(input, kernel_size=3, stride=2)
# Variable containing:
# (0 ,.,.) =
# 2 4 6
# [torch.FloatTensor of size 1x1x3]
torch.nn.functional.avg_pool2d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
在 kh x kw 区域中应用步长为 dh x dw 的二维平均池化操作。输出特征的数量等于输入平面的数量。
参数:
input– 输入的张量(minibatch x in_channels x iH x iW)kernel_size– 池化区域的大小,可以是单个数字或者元组(kh x kw)stride– 池化操作的步长,可以是单个数字或者元组(sh x sw)。默认等于核的大小padding– 在输入上隐式的零填充,可以是单个数字或者一个元组(padh x padw),默认:0ceil_mode– 定义空间输出形状的操作count_include_pad– 除以原始非填充图像内的元素数量或kh * kw
torch.nn.functional.avg_pool3d(input, kernel_size, stride=None)
在 kt x kh x kw 区域中应用步长为 dt x dh x dw 的三维平均池化操作。输出特征的数量等于 input planes / dt。
torch.nn.functional.max_pool1d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行一维最大池化。
torch.nn.functional.max_pool2d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行二维最大池化。
torch.nn.functional.max_pool3d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行三维最大池化。
torch.nn.functional.max_unpool1d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
一维最大池化逆操作。
torch.nn.functional.max_unpool2d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
二维最大池化逆操作。
torch.nn.functional.max_unpool3d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
三维最大池化逆操作。
torch.nn.functional.lp_pool2d(input, norm_type, kernel_size, stride=None, ceil_mode=False)
二维 Lp 池化操作。
torch.nn.functional.adaptive_max_pool1d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 1D 自适应最大池化。
参数:
output_size– 目标输出大小(单个整数)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_max_pool2d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 2D 自适应最大池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_avg_pool1d(input, output_size)
在由几个输入平面组成的输入信号上应用 1D 自适应平均池化。
参数:
output_size– 目标输出大小(单个整数)
torch.nn.functional.adaptive_avg_pool2d(input, output_size)
在由几个输入平面组成的输入信号上应用 2D 自适应平均池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)
17. 激活函数 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.threshold(input, threshold, value, inplace=False) | 阈值激活函数 |
torch.nn.functional.relu(input, inplace=False) | ReLU 激活函数 |
torch.nn.functional.hardtanh(input, min_val=-1., max_val=1., inplace=False) | HardTanh 激活函数 |
torch.nn.functional.relu6(input, inplace=False) | ReLU6 激活函数 |
torch.nn.functional.elu(input, alpha=1.0, inplace=False) | ELU 激活函数 |
torch.nn.functional.leaky_relu(input, negative_slope=0.01, inplace=False) | Leaky ReLU 激活函数 |
torch.nn.functional.prelu(input, weight) | PReLU 激活函数 |
torch.nn.functional.rrelu(input, lower=0.125, upper=0.3333333333333333, training=False, inplace=False) | RReLU 激活函数 |
torch.nn.functional.logsigmoid(input) | LogSigmoid 激活函数 |
torch.nn.functional.hardshrink(input, lambd=0.5) | HardShrink 激活函数 |
torch.nn.functional.tanhshrink(input) | TanhShrink 激活函数 |
torch.nn.functional.softsign(input) | SoftSign 激活函数 |
torch.nn.functional.softplus(input, beta=1, threshold=20) | Softplus 激活函数 |
torch.nn.functional.softmin(input) | Softmin 激活函数 |
torch.nn.functional.softmax(input) | Softmax 激活函数 |
torch.nn.functional.softshrink(input, lambd=0.5) | Softshrink 激活函数 |
torch.nn.functional.log_softmax(input) | LogSoftmax 激活函数 |
torch.nn.functional.tanh(input) | Tanh 激活函数 |
torch.nn.functional.sigmoid(input) | Sigmoid 激活函数 |
18. Normalization 标准化 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.batch_norm(input, running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-05) | 批量归一化 |
torch.nn.functional.normalize(input, p=2.0, dim=1, eps=1e-12, out=None) | Lp 归一化 |
19. 线性函数 函数式接口
torch.nn.functional.linear(input, weight, bias=None)
对输入进行线性变换:$y = xA^T + b$。
20. Dropout 函数式接口
torch.nn.functional.dropout(input, p=0.5, training=False, inplace=False)
在训练期间,以概率 p 随机将输入张量的某些元素置零。
21. 距离函数 函数式接口
torch.nn.functional.pairwise_distance(x1, x2, p=2, eps=1e-06)
计算两个输入张量之间的成对距离(p-norm)。
参数:
x1– 第一个输入的张量x2– 第二个输入的张量p– 矩阵范数的维度。默认值是2,即二范数
示例:
input1 = autograd.Variable(torch.randn(100, 128))
input2 = autograd.Variable(torch.randn(100, 128))
output = F.pairwise_distance(input1, input2, p=2)
output.backward()
22. 损失函数 函数式接口
torch.nn.functional.nll_loss(input, target, weight=None, size_average=True)
负的 log likelihood 损失函数。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.kl_div(input, target, size_average=True)
KL 散度损失函数。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variablesize_average– 如果为True,loss 则是平均值,需要除以输入 tensor 中 element 的数目
torch.nn.functional.cross_entropy(input, target, weight=None, size_average=True)
该函数使用了 log_softmax 和 nll_loss。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.binary_cross_entropy(input, target, weight=None, size_average=True)
该函数计算了输出与 target 之间的二进制交叉熵。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variableweight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.smooth_l1_loss(input, target, size_average=True)
平滑版 L1 loss。如果绝对误差低于 1,则使用平方项,否则使用 L1 项。
其他损失函数详解
torch.nn.KLDivLoss(weight=None, size_average=True)
计算 KL 散度损失。
torch.nn.BCELoss(weight=None, size_average=True)
计算 target 与 output 之间的二进制交叉熵。
torch.nn.MarginRankingLoss(margin=0, size_average=True)
创建一个标准,给定输入 x1、x2 两个 1-D Tensor,和一个标签 y(1-D mini-batch tensor),y 里面的值只能是 -1 或 1。
torch.nn.HingeEmbeddingLoss(size_average=True)
给定一个输入 $x$(2-D mini-batch tensor)和对应的标签 $y$(1-D tensor,值为 1 或 -1),此函数用来计算之间的损失值。
torch.nn.MultiLabelMarginLoss(size_average=True)
计算多标签分类的 hinge loss(margin-based loss),计算 loss 时需要两个输入:
- input $x$:2-D mini-batch Tensor
- output $y$:2-D Tensor,表示 mini-batch 中样本类别的索引
torch.nn.SmoothL1Loss(size_average=True)
平滑版 L1 loss。
torch.nn.SoftMarginLoss(size_average=True)
创建一个标准,用来优化 2 分类的 logistic loss。输入为 $x$(一个 2-D mini-batch Tensor)和目标 $y$(一个包含 1 或 -1 的 Tensor)。
torch.nn.MultiLabelSoftMarginLoss(weight=None, size_average=True)
创建一个标准,基于输入 $x$ 和目标 $y$ 的 max-entropy,优化多标签 one-versus-all 的损失。
torch.nn.CosineEmbeddingLoss(margin=0, size_average=True)
给定输入 Tensors x1、x2 和一个标签 Tensor $y$(元素的值为 1 或 -1)。此标准使用 cosine 距离测量两个输入是否相似,一般用来学习非线性 embedding 或者半监督学习。
torch.nn.MultiMarginLoss(p=1, margin=1, weight=None, size_average=True)
用来计算 multi-class classification 的 hinge loss(margin-based loss)。
12. 图像处理层
torch.nn.PixelShuffle(upscale_factor)
将 shape 为 [N, C*r^2, H, W] 的 Tensor 重新排列为 shape 为 [N, C, H*r, W*r] 的 Tensor。
参数说明:
upscale_factor(int) – 增加空间分辨率的因子
示例:
ps = nn.PixelShuffle(3)
input = autograd.Variable(torch.Tensor(1, 9, 4, 4))
output = ps(input)
print(output.size())
# torch.Size([1, 1, 12, 12])
torch.nn.UpsamplingNearest2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D 最近邻上采样。
参数说明:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingNearest2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1 1 2 2
# 1 1 2 2
# 3 3 4 4
# 3 3 4 4
# [torch.FloatTensor of size 1x1x4x4]
torch.nn.UpsamplingBilinear2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D bilinear 上采样。
参数:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingBilinear2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1.0000 1.3333 1.6667 2.0000
# 1.6667 2.0000 2.3333 2.6667
# 2.3333 2.6667 3.0000 3.3333
# 3.0000 3.3333 3.6667 4.0000
# [torch.FloatTensor of size 1x1x4x4]
13. 多 GPU 并行
torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0)
在模块级别上实现数据并行。
参数说明:
module– 要被并行的 moduledevice_ids– CUDA 设备,默认为所有设备output_device– 输出设备(默认为device_ids[0])
示例:
net = torch.nn.DataParallel(model, device_ids=[0, 1, 2])
output = net(input_var)
14. 工具函数
torch.nn.utils.clip_grad_norm(parameters, max_norm, norm_type=2)
正则项的值由所有的梯度计算出来,就像他们连成一个向量一样。梯度被 in-place operation 修改。
参数说明:
parameters(Iterable[Variable]) – 可迭代的 Variables,它们的梯度即将被标准化max_norm(float or int) – clip 后,gradients p-norm 值norm_type(float or int) – 标准化的类型,p-norm,可以是inf代表 infinity norm
torch.nn.utils.pad_sequence(sequences, batch_first=True, padding_value=0)
将一个列表中的多个序列(如多个一维张量)填充为具有相同长度的二维张量。
参数说明:
sequences– 一个包含多个一维张量的列表,每个张量代表一个序列batch_first– 布尔值,指示返回的张量是否以批处理维度作为第一个维度(True)还是以序列长度作为第一个维度(False)。默认为Falsepadding_value– 用于填充的值,默认为0
torch.nn.utils.rnn.PackedSequence(_cls, data, batch_sizes)
所有的 RNN 模块都接收这种被包裹后的序列作为它们的输入。
参数说明:
data(Variable) – 包含打包后序列的 Variablebatch_sizes(list[int]) – 包含 mini-batch 中每个序列长度的列表
torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_first=False)
将一个填充过的变长序列压紧。
参数说明:
input(Variable) – 变长序列被填充后的 batchlengths(list[int]) – Variable 中每个序列的长度batch_first(bool, optional) – 如果是True,input 的形状应该是B*T*size
torch.nn.utils.rnn.pad_packed_sequence(sequence, batch_first=False)
和 pack_padded_sequence() 相反。把压紧的序列再填充回来。
参数说明:
sequence(PackedSequence) – 将要被填充的 batchbatch_first(bool, optional) – 如果为True,返回的数据的格式为B×T×*
示例:
import torch
import torch.nn as nn
from torch.autograd import Variable
from torch.nn import utils as nn_utils
batch_size = 2
max_length = 3
hidden_size = 2
n_layers = 1
tensor_in = torch.FloatTensor([[1, 2, 3], [1, 0, 0]]).resize_(2, 3, 1)
tensor_in = Variable(tensor_in) # [batch, seq, feature], [2, 3, 1]
seq_lengths = [3, 1] # list of integers holding information about the batch size at each sequence step
# pack it
pack = nn_utils.rnn.pack_padded_sequence(tensor_in, seq_lengths, batch_first=True)
# initialize
rnn = nn.RNN(1, hidden_size, n_layers, batch_first=True)
h0 = Variable(torch.randn(n_layers, batch_size, hidden_size))
# forward
out, _ = rnn(pack, h0)
# unpack
unpacked = nn_utils.rnn.pad_packed_sequence(out)
print(unpacked)
torch.utils.data.Dataset
表示 Dataset 的抽象类。所有其他数据集都应该进行子类化。所有子类应该覆写 __len__ 和 __getitem__,前者提供了数据集的大小,后者支持整数索引,范围从 0 到 len(self)。
torch.utils.data.TensorDataset(data_tensor, target_tensor)
包装数据和目标张量的数据集。通过沿着第一个维度索引两个张量来恢复每个样本。
参数:
data_tensor(Tensor) – 包含样本数据target_tensor(Tensor) – 包含样本目标(标签)
torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=<function default_collate>, pin_memory=False, drop_last=False)
数据加载器。组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。
参数:
dataset(Dataset) – 加载数据的数据集batch_size(int, optional) – 每个 batch 加载多少个样本(默认:1)shuffle(bool, optional) – 设置为True时会在每个 epoch 重新打乱数据(默认:False)sampler(Sampler, optional) – 定义从数据集中提取样本的策略。如果指定,则忽略shuffle参数num_workers(int, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认:0)collate_fn(callable, optional) – 将样本合并成 batch 的函数pin_memory(bool, optional) – 是否将数据拷贝到 CUDA 固定内存drop_last(bool, optional) – 如果数据集大小不能被 batch size 整除,则设置为True后可删除最后一个不完整的 batch。如果设为False并且数据集的大小不能被 batch size 整除,则最后一个 batch 将更小(默认:False)
torch.utils.data.sampler.Sampler(data_source)
所有采样器的基础类。每个采样器子类必须提供一个 __iter__ 方法,提供一种迭代数据集元素的索引的方法,以及返回迭代器长度的 __len__ 方法。
torch.utils.data.sampler.SequentialSampler(data_source)
样本元素顺序排列,始终以相同的顺序。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.RandomSampler(data_source)
样本元素随机,没有替换。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.SubsetRandomSampler(indices)
样本元素从指定的索引列表中随机抽取,没有替换。
参数:
indices(list) – 索引的列表
torch.utils.data.sampler.WeightedRandomSampler(weights, num_samples, replacement=True)
样本元素来自于 [0, ..., len(weights)-1],给定概率(weights)。
参数:
weights(list) – 权重列表,没必要加起来为1num_samples(int) – 抽样数量
15. Convolution 卷积层函数式接口
torch.nn.functional.conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 1D 卷积。
参数说明:
input– 输入张量的形状(minibatch x in_channels x iW)weight– 过滤器的形状(out_channels, in_channels, kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,默认为1
示例:
filters = autograd.Variable(torch.randn(33, 16, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50))
F.conv1d(inputs, filters)
torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 2D 卷积。
参数:
input– 输入张量(minibatch x in_channels x iH x iW)weight– 过滤器张量(out_channels, in_channels/groups, kH, kW)bias– 可选偏置张量(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0groups– 将输入分成组,in_channels应该被组数除尽
示例:
# With square kernels and equal stride
filters = autograd.Variable(torch.randn(8, 4, 3, 3))
inputs = autograd.Variable(torch.randn(1, 4, 5, 5))
F.conv2d(inputs, filters, padding=1)
torch.nn.functional.conv3d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 3D 卷积。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器张量的形状(out_channels, in_channels, kT, kH, kW)bias– 可选偏置张量的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0
示例:
filters = autograd.Variable(torch.randn(33, 16, 3, 3, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50, 10, 20))
F.conv3d(inputs, filters)
torch.nn.functional.conv_transpose1d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用一维转置卷积,有时也称为”去卷积”。
torch.nn.functional.conv_transpose2d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用二维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0groups– 将输入分成组,in_channels应该被组数除尽output_padding–0 <= padding < stride的零填充,应该添加到输出。可以是单个数字或元组。默认值:0
torch.nn.functional.conv_transpose3d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用三维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0
16. Pooling 池化层函数式接口
torch.nn.functional.avg_pool1d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
对由几个输入平面组成的输入信号进行一维平均池化。
参数:
kernel_size– 窗口的大小stride– 窗口的步长。默认值为kernel_sizepadding– 在两边添加隐式零填充ceil_mode– 当为True时,将使用ceil代替floor来计算输出形状count_include_pad– 当为True时,这将在平均计算时包括补零
示例:
# pool of square window of size=3, stride=2
input = Variable(torch.Tensor([[[1, 2, 3, 4, 5, 6, 7]]]))
F.avg_pool1d(input, kernel_size=3, stride=2)
# Variable containing:
# (0 ,.,.) =
# 2 4 6
# [torch.FloatTensor of size 1x1x3]
torch.nn.functional.avg_pool2d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
在 kh x kw 区域中应用步长为 dh x dw 的二维平均池化操作。输出特征的数量等于输入平面的数量。
参数:
input– 输入的张量(minibatch x in_channels x iH x iW)kernel_size– 池化区域的大小,可以是单个数字或者元组(kh x kw)stride– 池化操作的步长,可以是单个数字或者元组(sh x sw)。默认等于核的大小padding– 在输入上隐式的零填充,可以是单个数字或者一个元组(padh x padw),默认:0ceil_mode– 定义空间输出形状的操作count_include_pad– 除以原始非填充图像内的元素数量或kh * kw
torch.nn.functional.avg_pool3d(input, kernel_size, stride=None)
在 kt x kh x kw 区域中应用步长为 dt x dh x dw 的三维平均池化操作。输出特征的数量等于 input planes / dt。
torch.nn.functional.max_pool1d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行一维最大池化。
torch.nn.functional.max_pool2d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行二维最大池化。
torch.nn.functional.max_pool3d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行三维最大池化。
torch.nn.functional.max_unpool1d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
一维最大池化逆操作。
torch.nn.functional.max_unpool2d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
二维最大池化逆操作。
torch.nn.functional.max_unpool3d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
三维最大池化逆操作。
torch.nn.functional.lp_pool2d(input, norm_type, kernel_size, stride=None, ceil_mode=False)
二维 Lp 池化操作。
torch.nn.functional.adaptive_max_pool1d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 1D 自适应最大池化。
参数:
output_size– 目标输出大小(单个整数)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_max_pool2d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 2D 自适应最大池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_avg_pool1d(input, output_size)
在由几个输入平面组成的输入信号上应用 1D 自适应平均池化。
参数:
output_size– 目标输出大小(单个整数)
torch.nn.functional.adaptive_avg_pool2d(input, output_size)
在由几个输入平面组成的输入信号上应用 2D 自适应平均池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)
17. 激活函数 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.threshold(input, threshold, value, inplace=False) | 阈值激活函数 |
torch.nn.functional.relu(input, inplace=False) | ReLU 激活函数 |
torch.nn.functional.hardtanh(input, min_val=-1., max_val=1., inplace=False) | HardTanh 激活函数 |
torch.nn.functional.relu6(input, inplace=False) | ReLU6 激活函数 |
torch.nn.functional.elu(input, alpha=1.0, inplace=False) | ELU 激活函数 |
torch.nn.functional.leaky_relu(input, negative_slope=0.01, inplace=False) | Leaky ReLU 激活函数 |
torch.nn.functional.prelu(input, weight) | PReLU 激活函数 |
torch.nn.functional.rrelu(input, lower=0.125, upper=0.3333333333333333, training=False, inplace=False) | RReLU 激活函数 |
torch.nn.functional.logsigmoid(input) | LogSigmoid 激活函数 |
torch.nn.functional.hardshrink(input, lambd=0.5) | HardShrink 激活函数 |
torch.nn.functional.tanhshrink(input) | TanhShrink 激活函数 |
torch.nn.functional.softsign(input) | SoftSign 激活函数 |
torch.nn.functional.softplus(input, beta=1, threshold=20) | Softplus 激活函数 |
torch.nn.functional.softmin(input) | Softmin 激活函数 |
torch.nn.functional.softmax(input) | Softmax 激活函数 |
torch.nn.functional.softshrink(input, lambd=0.5) | Softshrink 激活函数 |
torch.nn.functional.log_softmax(input) | LogSoftmax 激活函数 |
torch.nn.functional.tanh(input) | Tanh 激活函数 |
torch.nn.functional.sigmoid(input) | Sigmoid 激活函数 |
18. Normalization 标准化 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.batch_norm(input, running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-05) | 批量归一化 |
torch.nn.functional.normalize(input, p=2.0, dim=1, eps=1e-12, out=None) | Lp 归一化 |
19. 线性函数 函数式接口
torch.nn.functional.linear(input, weight, bias=None)
对输入进行线性变换:$y = xA^T + b$。
20. Dropout 函数式接口
torch.nn.functional.dropout(input, p=0.5, training=False, inplace=False)
在训练期间,以概率 p 随机将输入张量的某些元素置零。
21. 距离函数 函数式接口
torch.nn.functional.pairwise_distance(x1, x2, p=2, eps=1e-06)
计算两个输入张量之间的成对距离(p-norm)。
参数:
x1– 第一个输入的张量x2– 第二个输入的张量p– 矩阵范数的维度。默认值是2,即二范数
示例:
input1 = autograd.Variable(torch.randn(100, 128))
input2 = autograd.Variable(torch.randn(100, 128))
output = F.pairwise_distance(input1, input2, p=2)
output.backward()
22. 损失函数 函数式接口
torch.nn.functional.nll_loss(input, target, weight=None, size_average=True)
负的 log likelihood 损失函数。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.kl_div(input, target, size_average=True)
KL 散度损失函数。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variablesize_average– 如果为True,loss 则是平均值,需要除以输入 tensor 中 element 的数目
torch.nn.functional.cross_entropy(input, target, weight=None, size_average=True)
该函数使用了 log_softmax 和 nll_loss。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.binary_cross_entropy(input, target, weight=None, size_average=True)
该函数计算了输出与 target 之间的二进制交叉熵。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variableweight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.smooth_l1_loss(input, target, size_average=True)
平滑版 L1 loss。如果绝对误差低于 1,则使用平方项,否则使用 L1 项。
12. 图像处理层
torch.nn.PixelShuffle(upscale_factor)
将 shape 为 [N, C*r^2, H, W] 的 Tensor 重新排列为 shape 为 [N, C, H*r, W*r] 的 Tensor。
参数说明:
upscale_factor(int) – 增加空间分辨率的因子
示例:
ps = nn.PixelShuffle(3)
input = autograd.Variable(torch.Tensor(1, 9, 4, 4))
output = ps(input)
print(output.size())
# torch.Size([1, 1, 12, 12])
torch.nn.UpsamplingNearest2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D 最近邻上采样。
参数说明:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingNearest2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1 1 2 2
# 1 1 2 2
# 3 3 4 4
# 3 3 4 4
# [torch.FloatTensor of size 1x1x4x4]
torch.nn.UpsamplingBilinear2d(size=None, scale_factor=None)
对于多 channel 输入进行 2-D bilinear 上采样。
参数:
size(tuple, optional) – 一个包含两个整数的元组(H_out, W_out)指定了输出的长宽scale_factor(int, optional) – 长和宽的一个乘子
示例:
# inp = Variable containing:
# (0 ,0 ,.,.) =
# 1 2
# 3 4
# [torch.FloatTensor of size 1x1x2x2]
m = nn.UpsamplingBilinear2d(scale_factor=2)
m(inp)
# Variable containing:
# (0 ,0 ,.,.) =
# 1.0000 1.3333 1.6667 2.0000
# 1.6667 2.0000 2.3333 2.6667
# 2.3333 2.6667 3.0000 3.3333
# 3.0000 3.3333 3.6667 4.0000
# [torch.FloatTensor of size 1x1x4x4]
13. 多 GPU 并行
torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0)
在模块级别上实现数据并行。
参数说明:
module– 要被并行的 moduledevice_ids– CUDA 设备,默认为所有设备output_device– 输出设备(默认为device_ids[0])
示例:
net = torch.nn.DataParallel(model, device_ids=[0, 1, 2])
output = net(input_var)
14. 工具函数
torch.nn.utils.clip_grad_norm(parameters, max_norm, norm_type=2)
正则项的值由所有的梯度计算出来,就像他们连成一个向量一样。梯度被 in-place operation 修改。
参数说明:
parameters(Iterable[Variable]) – 可迭代的 Variables,它们的梯度即将被标准化max_norm(float or int) – clip 后,gradients p-norm 值norm_type(float or int) – 标准化的类型,p-norm,可以是inf代表 infinity norm
torch.nn.utils.pad_sequence(sequences, batch_first=True, padding_value=0)
将一个列表中的多个序列(如多个一维张量)填充为具有相同长度的二维张量。
参数说明:
sequences– 一个包含多个一维张量的列表,每个张量代表一个序列batch_first– 布尔值,指示返回的张量是否以批处理维度作为第一个维度(True)还是以序列长度作为第一个维度(False)。默认为Falsepadding_value– 用于填充的值,默认为0
torch.nn.utils.rnn.PackedSequence(_cls, data, batch_sizes)
所有的 RNN 模块都接收这种被包裹后的序列作为它们的输入。
参数说明:
data(Variable) – 包含打包后序列的 Variablebatch_sizes(list[int]) – 包含 mini-batch 中每个序列长度的列表
torch.nn.utils.rnn.pack_padded_sequence(input, lengths, batch_first=False)
将一个填充过的变长序列压紧。
参数说明:
input(Variable) – 变长序列被填充后的 batchlengths(list[int]) – Variable 中每个序列的长度batch_first(bool, optional) – 如果是True,input 的形状应该是B*T*size
torch.nn.utils.rnn.pad_packed_sequence(sequence, batch_first=False)
和 pack_padded_sequence() 相反。把压紧的序列再填充回来。
参数说明:
sequence(PackedSequence) – 将要被填充的 batchbatch_first(bool, optional) – 如果为True,返回的数据的格式为B×T×*
示例:
import torch
import torch.nn as nn
from torch.autograd import Variable
from torch.nn import utils as nn_utils
batch_size = 2
max_length = 3
hidden_size = 2
n_layers = 1
tensor_in = torch.FloatTensor([[1, 2, 3], [1, 0, 0]]).resize_(2, 3, 1)
tensor_in = Variable(tensor_in) # [batch, seq, feature], [2, 3, 1]
seq_lengths = [3, 1] # list of integers holding information about the batch size at each sequence step
# pack it
pack = nn_utils.rnn.pack_padded_sequence(tensor_in, seq_lengths, batch_first=True)
# initialize
rnn = nn.RNN(1, hidden_size, n_layers, batch_first=True)
h0 = Variable(torch.randn(n_layers, batch_size, hidden_size))
# forward
out, _ = rnn(pack, h0)
# unpack
unpacked = nn_utils.rnn.pad_packed_sequence(out)
print(unpacked)
torch.utils.data.Dataset
表示 Dataset 的抽象类。所有其他数据集都应该进行子类化。所有子类应该覆写 __len__ 和 __getitem__,前者提供了数据集的大小,后者支持整数索引,范围从 0 到 len(self)。
torch.utils.data.TensorDataset(data_tensor, target_tensor)
包装数据和目标张量的数据集。通过沿着第一个维度索引两个张量来恢复每个样本。
参数:
data_tensor(Tensor) – 包含样本数据target_tensor(Tensor) – 包含样本目标(标签)
torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=<function default_collate>, pin_memory=False, drop_last=False)
数据加载器。组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。
参数:
dataset(Dataset) – 加载数据的数据集batch_size(int, optional) – 每个 batch 加载多少个样本(默认:1)shuffle(bool, optional) – 设置为True时会在每个 epoch 重新打乱数据(默认:False)sampler(Sampler, optional) – 定义从数据集中提取样本的策略。如果指定,则忽略shuffle参数num_workers(int, optional) – 用多少个子进程加载数据。0表示数据将在主进程中加载(默认:0)collate_fn(callable, optional) – 将样本合并成 batch 的函数pin_memory(bool, optional) – 是否将数据拷贝到 CUDA 固定内存drop_last(bool, optional) – 如果数据集大小不能被 batch size 整除,则设置为True后可删除最后一个不完整的 batch。如果设为False并且数据集的大小不能被 batch size 整除,则最后一个 batch 将更小(默认:False)
torch.utils.data.sampler.Sampler(data_source)
所有采样器的基础类。每个采样器子类必须提供一个 __iter__ 方法,提供一种迭代数据集元素的索引的方法,以及返回迭代器长度的 __len__ 方法。
torch.utils.data.sampler.SequentialSampler(data_source)
样本元素顺序排列,始终以相同的顺序。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.RandomSampler(data_source)
样本元素随机,没有替换。
参数:
data_source(Dataset) – 采样的数据集
torch.utils.data.sampler.SubsetRandomSampler(indices)
样本元素从指定的索引列表中随机抽取,没有替换。
参数:
indices(list) – 索引的列表
torch.utils.data.sampler.WeightedRandomSampler(weights, num_samples, replacement=True)
样本元素来自于 [0, ..., len(weights)-1],给定概率(weights)。
参数:
weights(list) – 权重列表,没必要加起来为1num_samples(int) – 抽样数量
15. Convolution 卷积层函数式接口
torch.nn.functional.conv1d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 1D 卷积。
参数说明:
input– 输入张量的形状(minibatch x in_channels x iW)weight– 过滤器的形状(out_channels, in_channels, kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,默认为1
示例:
filters = autograd.Variable(torch.randn(33, 16, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50))
F.conv1d(inputs, filters)
torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 2D 卷积。
参数:
input– 输入张量(minibatch x in_channels x iH x iW)weight– 过滤器张量(out_channels, in_channels/groups, kH, kW)bias– 可选偏置张量(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0groups– 将输入分成组,in_channels应该被组数除尽
示例:
# With square kernels and equal stride
filters = autograd.Variable(torch.randn(8, 4, 3, 3))
inputs = autograd.Variable(torch.randn(1, 4, 5, 5))
F.conv2d(inputs, filters, padding=1)
torch.nn.functional.conv3d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)
对几个输入平面组成的输入信号应用 3D 卷积。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器张量的形状(out_channels, in_channels, kT, kH, kW)bias– 可选偏置张量的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认为1padding– 输入上隐含零填充。可以是单个数字或元组。默认值:0
示例:
filters = autograd.Variable(torch.randn(33, 16, 3, 3, 3))
inputs = autograd.Variable(torch.randn(20, 16, 50, 10, 20))
F.conv3d(inputs, filters)
torch.nn.functional.conv_transpose1d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用一维转置卷积,有时也称为”去卷积”。
torch.nn.functional.conv_transpose2d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用二维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0groups– 将输入分成组,in_channels应该被组数除尽output_padding–0 <= padding < stride的零填充,应该添加到输出。可以是单个数字或元组。默认值:0
torch.nn.functional.conv_transpose3d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1)
在由几个输入平面组成的输入图像上应用三维转置卷积,有时也称为”去卷积”。
参数:
input– 输入张量的形状(minibatch x in_channels x iT x iH x iW)weight– 过滤器的形状(in_channels x out_channels x kH x kW)bias– 可选偏置的形状(out_channels)stride– 卷积核的步长,可以是单个数字或一个元组(sh x sw)。默认:1padding– 输入上隐含零填充。可以是单个数字或元组(padh x padw)。默认:0
16. Pooling 池化层函数式接口
torch.nn.functional.avg_pool1d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
对由几个输入平面组成的输入信号进行一维平均池化。
参数:
kernel_size– 窗口的大小stride– 窗口的步长。默认值为kernel_sizepadding– 在两边添加隐式零填充ceil_mode– 当为True时,将使用ceil代替floor来计算输出形状count_include_pad– 当为True时,这将在平均计算时包括补零
示例:
# pool of square window of size=3, stride=2
input = Variable(torch.Tensor([[[1, 2, 3, 4, 5, 6, 7]]]))
F.avg_pool1d(input, kernel_size=3, stride=2)
# Variable containing:
# (0 ,.,.) =
# 2 4 6
# [torch.FloatTensor of size 1x1x3]
torch.nn.functional.avg_pool2d(input, kernel_size, stride=None, padding=0, ceil_mode=False, count_include_pad=True)
在 kh x kw 区域中应用步长为 dh x dw 的二维平均池化操作。输出特征的数量等于输入平面的数量。
参数:
input– 输入的张量(minibatch x in_channels x iH x iW)kernel_size– 池化区域的大小,可以是单个数字或者元组(kh x kw)stride– 池化操作的步长,可以是单个数字或者元组(sh x sw)。默认等于核的大小padding– 在输入上隐式的零填充,可以是单个数字或者一个元组(padh x padw),默认:0ceil_mode– 定义空间输出形状的操作count_include_pad– 除以原始非填充图像内的元素数量或kh * kw
torch.nn.functional.avg_pool3d(input, kernel_size, stride=None)
在 kt x kh x kw 区域中应用步长为 dt x dh x dw 的三维平均池化操作。输出特征的数量等于 input planes / dt。
torch.nn.functional.max_pool1d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行一维最大池化。
torch.nn.functional.max_pool2d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行二维最大池化。
torch.nn.functional.max_pool3d(input, kernel_size, stride=None, padding=0, dilation=1, ceil_mode=False, return_indices=False)
对由几个输入平面组成的输入信号进行三维最大池化。
torch.nn.functional.max_unpool1d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
一维最大池化逆操作。
torch.nn.functional.max_unpool2d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
二维最大池化逆操作。
torch.nn.functional.max_unpool3d(input, indices, kernel_size, stride=None, padding=0, output_size=None)
三维最大池化逆操作。
torch.nn.functional.lp_pool2d(input, norm_type, kernel_size, stride=None, ceil_mode=False)
二维 Lp 池化操作。
torch.nn.functional.adaptive_max_pool1d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 1D 自适应最大池化。
参数:
output_size– 目标输出大小(单个整数)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_max_pool2d(input, output_size, return_indices=False)
在由几个输入平面组成的输入信号上应用 2D 自适应最大池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)return_indices– 是否返回池化的指数
torch.nn.functional.adaptive_avg_pool1d(input, output_size)
在由几个输入平面组成的输入信号上应用 1D 自适应平均池化。
参数:
output_size– 目标输出大小(单个整数)
torch.nn.functional.adaptive_avg_pool2d(input, output_size)
在由几个输入平面组成的输入信号上应用 2D 自适应平均池化。
参数:
output_size– 目标输出大小(单整数或双整数元组)
17. 激活函数 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.threshold(input, threshold, value, inplace=False) | 阈值激活函数 |
torch.nn.functional.relu(input, inplace=False) | ReLU 激活函数 |
torch.nn.functional.hardtanh(input, min_val=-1., max_val=1., inplace=False) | HardTanh 激活函数 |
torch.nn.functional.relu6(input, inplace=False) | ReLU6 激活函数 |
torch.nn.functional.elu(input, alpha=1.0, inplace=False) | ELU 激活函数 |
torch.nn.functional.leaky_relu(input, negative_slope=0.01, inplace=False) | Leaky ReLU 激活函数 |
torch.nn.functional.prelu(input, weight) | PReLU 激活函数 |
torch.nn.functional.rrelu(input, lower=0.125, upper=0.3333333333333333, training=False, inplace=False) | RReLU 激活函数 |
torch.nn.functional.logsigmoid(input) | LogSigmoid 激活函数 |
torch.nn.functional.hardshrink(input, lambd=0.5) | HardShrink 激活函数 |
torch.nn.functional.tanhshrink(input) | TanhShrink 激活函数 |
torch.nn.functional.softsign(input) | SoftSign 激活函数 |
torch.nn.functional.softplus(input, beta=1, threshold=20) | Softplus 激活函数 |
torch.nn.functional.softmin(input) | Softmin 激活函数 |
torch.nn.functional.softmax(input) | Softmax 激活函数 |
torch.nn.functional.softshrink(input, lambd=0.5) | Softshrink 激活函数 |
torch.nn.functional.log_softmax(input) | LogSoftmax 激活函数 |
torch.nn.functional.tanh(input) | Tanh 激活函数 |
torch.nn.functional.sigmoid(input) | Sigmoid 激活函数 |
18. Normalization 标准化 函数式接口
| 函数 | 说明 |
|---|---|
torch.nn.functional.batch_norm(input, running_mean, running_var, weight=None, bias=None, training=False, momentum=0.1, eps=1e-05) | 批量归一化 |
torch.nn.functional.normalize(input, p=2.0, dim=1, eps=1e-12, out=None) | Lp 归一化 |
19. 线性函数 函数式接口
torch.nn.functional.linear(input, weight, bias=None)
对输入进行线性变换:$y = xA^T + b$。
20. Dropout 函数式接口
torch.nn.functional.dropout(input, p=0.5, training=False, inplace=False)
在训练期间,以概率 p 随机将输入张量的某些元素置零。
21. 距离函数 函数式接口
torch.nn.functional.pairwise_distance(x1, x2, p=2, eps=1e-06)
计算两个输入张量之间的成对距离(p-norm)。
参数:
x1– 第一个输入的张量x2– 第二个输入的张量p– 矩阵范数的维度。默认值是2,即二范数
示例:
input1 = autograd.Variable(torch.randn(100, 128))
input2 = autograd.Variable(torch.randn(100, 128))
output = F.pairwise_distance(input1, input2, p=2)
output.backward()
22. 损失函数 函数式接口
torch.nn.functional.nll_loss(input, target, weight=None, size_average=True)
负的 log likelihood 损失函数。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.kl_div(input, target, size_average=True)
KL 散度损失函数。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variablesize_average– 如果为True,loss 则是平均值,需要除以输入 tensor 中 element 的数目
torch.nn.functional.cross_entropy(input, target, weight=None, size_average=True)
该函数使用了 log_softmax 和 nll_loss。
参数:
input–(N, C)其中 C 是类别的个数target–(N)其大小是0 <= targets[i] <= C-1weight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.binary_cross_entropy(input, target, weight=None, size_average=True)
该函数计算了输出与 target 之间的二进制交叉熵。
参数:
input– 任意形状的 Variabletarget– 与输入相同形状的 Variableweight(Variable, optional) – 一个可手动指定每个类别的权重。如果给定的话,必须是大小为nclasses的 Variablesize_average(bool, optional) – 默认情况下,是 mini-batch loss 的平均值,然而,如果size_average=False,则是 mini-batch loss 的总和
torch.nn.functional.smooth_l1_loss(input, target, size_average=True)
平滑版 L1 loss。如果绝对误差低于 1,则使用平方项,否则使用 L1 项。
23. 自动求导 torch.autograd
torch.autograd.backward(variables, grad_variables, retain_variables=False)
给定图的叶子节点 variables,计算图中变量的梯度和。
参数说明:
variables(variable 列表) – 被求微分的叶子节点,即 ysgrad_variables(Tensor 列表) – 对应 variable 的梯度。仅当 variable 不是标量且需要求梯度的时候使用retain_variables(bool) –True时,计算梯度时所需要的 buffer 在计算完梯度后不会被释放。如果想对一个子图多次求微分的话,需要设置为True
torch.autograd.Variable
包装一个 Tensor,并记录用在它身上的 operations。
变量:
data– 包含的 Tensorgrad– 保存着 Variable 的梯度。这个属性是懒分配的,且不能被重新分配requires_grad– 布尔值,指示这个 Variable 是否是被一个包含 Variable 的子图创建的。只能改变 leaf variable 的这个标签volatile– 布尔值,指示这个 Variable 是否被用于推断模式(即,不保存历史信息)。只能改变 leaf variable 的这个标签creator– 创建这个 Variable 的 Function,对于 leaf variable,这个属性为None。只读属性
torch.autograd.Variable.backward(gradient=None, retain_variables=False)
当前 Variable 对 leaf variable 求偏导。
参数:
gradient(Tensor) – 其他函数对于此 Variable 的导数。仅当 Variable 不是标量的时候使用,类型和形状应该和self.data一致retain_variables(bool) –True时,计算梯度所必要的 buffer 在经历过一次 backward 过程后不会被释放。如果你想多次计算某个子图的梯度的时候,设置为True。在某些情况下,使用autograd.backward()效率更高
torch.autograd.Variable.detach()
返回一个新的 Variable,从当前图中分离下来的。
torch.autograd.Variable.detach_()
将一个 Variable 从创建它的图中分离,并把它设置成 leaf variable。
torch.autograd.Variable.register_hook(hook)
注册一个 backward 钩子。每次 gradients 被计算的时候,这个 hook 都被调用。
示例:
v = Variable(torch.Tensor([0, 0, 0]), requires_grad=True)
h = v.register_hook(lambda grad: grad * 2) # double the gradient
v.backward(torch.Tensor([1, 1, 1]))
# 先计算原始梯度,再进 hook,获得一个新梯度。
print(v.grad.data)
# 2
# 2
# 2
# [torch.FloatTensor of size 3]
h.remove() # removes the hook
def w_hook(grad):
print("hello")
return None
w1 = Variable(torch.FloatTensor([1, 1, 1]), requires_grad=True)
w1.register_hook(w_hook) # 如果 hook 返回的是 None 的话,那么梯度还是原来计算的梯度。
w1.backward(gradient=torch.FloatTensor([1, 1, 1]))
print(w1.grad)
# hello
# Variable containing:
# 1
# 1
# 1
# [torch.FloatTensor of size 3]
torch.autograd.Variable.reinforce(reward)
注册一个奖励,这个奖励是由一个随机过程得到的。
参数:
reward(Tensor) – 每个元素的 reward。必须和 Variable 形状相同,并在同一个设备上
torch.autograd.Function
变量:
saved_tensors– 调用forward()时需要被保存的 Tensors 的 tupleneeds_input_grad– 长度为输入数量的布尔值组成的 tuple。指示给定的 input 是否需要梯度。这个被用来优化用于 backward 过程中的 buffer,忽略 backward 中的梯度计算num_inputs– forward 的输入参数数量num_outputs– forward 返回的 Tensor 数量requires_grad– 布尔值。指示 backward 以后会不会被调用previous_functions– 长度为num_inputs的Tuple of (int, Function)pairs。Tuple 中的每单元保存着创建 input 的 Function 的引用和索引
backward(*grad_output)
定义了 operation 的微分公式。所有的 Function 子类都应该重写这个方法。
forward(*input)
执行 operation。所有的 Function 子类都需要重写这个方法。
mark_dirty(*args)
将输入的 tensors 标记为被 in-place operation 修改过。
mark_non_differentiable(*args)
将输出标记为不可微。
mark_shared_storage(*pairs)
将给定的 tensors pairs 标记为共享存储空间。
save_for_backward(*tensors)
将传入的 tensor 保存起来,留着 backward 的时候用。
24. 自定义梯度计算:冻结参数的梯度更新 requires_grad_(False)
1. 冻结整个层的参数
import torch
import torch.nn as nn
# 定义一个简单的模型
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.fc1 = nn.Linear(10, 5) # 第一层
self.fc2 = nn.Linear(5, 2) # 第二层
def forward(self, x):
x = self.fc1(x)
x = self.fc2(x)
return x
# 实例化模型
model = MyModel()
# 冻结 fc1 层的所有参数
for param in model.fc1.parameters():
param.requires_grad = False
for name, param in model.named_parameters():
print(f"{name} requires_grad: {param.requires_grad}")
2. 冻结某个层的个别参数
import torch
import torch.nn as nn
# 定义一个简单的模型
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.fc1 = nn.Linear(10, 5) # 第一层
self.fc2 = nn.Linear(5, 2) # 第二层
def forward(self, x):
x = self.fc1(x)
x = self.fc2(x)
return x
# 实例化模型
model = MyModel()
# 例如,冻结 fc1 层的权重(weight)但允许偏置(bias)更新
model.fc1.weight.requires_grad = False # 只冻结权重
model.fc1.bias.requires_grad = True # 允许偏置更新
for name, param in model.named_parameters():
print(f"{name} requires_grad: {param.requires_grad}")
3. 控制更细粒度的参数,冻结某一层的个别参数 register_hook
import torch
import torch.nn as nn
# 定义一个简单的模型
class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.fc1 = nn.Linear(10, 5) # 第一层
self.fc2 = nn.Linear(5, 2) # 第二层
def forward(self, x):
x = self.fc1(x)
x = self.fc2(x)
return x
# 实例化模型
model = MyModel()
# 假设我们要冻结 fc1.weight 中某些特定位置的元素
def freeze_specific_weights(grad):
# freeze_specific_weights 函数会在反向传播过程中被调用
# 将特定位置的梯度置零,冻结这些位置的参数
grad[0, 0] = 0 # 冻结第一行第一列的权重
return grad
# 为 fc1 的权重注册一个 hook 来修改其梯度
model.fc1.weight.register_hook(freeze_specific_weights)
for name, param in model.named_parameters():
print(f"{name} requires_grad: {param.requires_grad}")
25. 优化器 torch.optim
使用示例
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)
为每个参数单独配置参数
optim.SGD([
{'params': model.base.parameters()},
{'params': model.classifier.parameters(), 'lr': 1e-3}
], lr=1e-2, momentum=0.9)
这意味着 model.base 的参数将会使用 1e-2 的学习率,model.classifier 的参数将会使用 1e-3 的学习率,并且 0.9 的 momentum 将会被用于所有的参数。
单次优化
使用方法 1:optimizer.step()
所有的 optimizer 都实现了 step() 方法,这个方法会更新所有的参数。
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
使用方法 2:optimizer.step(closure)
一些优化算法例如 Conjugate Gradient 和 LBFGS 需要重复多次计算函数,因此你需要传入一个闭包去允许它们重新计算你的模型。这个闭包应当清空梯度,计算损失,然后返回。
for input, target in dataset:
def closure():
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
return loss
optimizer.step(closure)
torch.optim.Optimizer(params, defaults)
所有优化器的基类。
参数:
params(iterable) – Variable 或者 dict 的 iterable。指定了什么参数应当被优化defaults(dict) – 包含了优化选项默认值的字典(一个参数组没有指定的参数选项将会使用默认值)
load_state_dict(state_dict)
加载 optimizer 状态。
参数:
state_dict(dict) – optimizer 的状态。应当是一个调用state_dict()所返回的对象
state_dict()
以 dict 返回 optimizer 的状态。
包含:
state– 一个保存了当前优化状态的 dict。optimizer 的类别不同,state 的内容也会不同param_groups– 一个包含了全部参数组的 dict
step(closure)
进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
zero_grad()
清空所有被优化过的 Variable 的梯度。
torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)
实现 Adadelta 算法。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictrho(float, 可选) – 用于计算平方梯度的运行平均值的系数(默认:0.9)eps(float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-6)lr(float, 可选) – 在 delta 被应用到参数更新之前对它缩放的系数(默认:1.0)weight_decay(float, 可选) – 权重衰减(L2 惩罚)(默认:0)
step(closure):进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0)
实现 Adagrad 算法。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictlr(float, 可选) – 学习率(默认:1e-2)lr_decay(float, 可选) – 学习率衰减(默认:0)weight_decay(float, 可选) – 权重衰减(L2 惩罚)(默认:0)
step(closure):单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
实现 Adam 算法。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictlr(float, 可选) – 学习率(默认:1e-3)betas(Tuple[float, float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9, 0.999)eps(float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)weight_decay(float, 可选) – 权重衰减(L2 惩罚)(默认:0)
step(closure):进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
实现 Adamax 算法(Adam 的一种基于无穷范数的变种)。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictlr(float, 可选) – 学习率(默认:2e-3)betas(Tuple[float, float], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数eps(float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)weight_decay(float, 可选) – 权重衰减(L2 惩罚)(默认:0)
step(closure):进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)
实现平均随机梯度下降算法。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictlr(float, 可选) – 学习率(默认:1e-2)lambd(float, 可选) – 衰减项(默认:1e-4)alpha(float, 可选) – eta 更新的指数(默认:0.75)t0(float, 可选) – 指明在哪一次开始平均化(默认:1e6)weight_decay(float, 可选) – 权重衰减(L2 惩罚)(默认:0)
step(closure):进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-05, tolerance_change=1e-09, history_size=100, line_search_fn=None)
实现 L-BFGS 算法。
参数:
lr(float) – 学习率(默认:1)max_iter(int) – 每一步优化的最大迭代次数(默认:20)max_eval(int) – 每一步优化的最大函数评价次数(默认:max * 1.25)tolerance_grad(float) – 一阶最优的终止容忍度(默认:1e-5)tolerance_change(float) – 在函数值/参数变化量上的终止容忍度(默认:1e-9)history_size(int) – 更新历史的大小(默认:100)
step(closure):进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
实现 RMSprop 算法。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictlr(float, 可选) – 学习率(默认:1e-2)momentum(float, 可选) – 动量因子(默认:0)alpha(float, 可选) – 平滑常数(默认:0.99)eps(float, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8)centered(bool, 可选) – 如果为True,计算中心化的 RMSprop,并且用它的方差预测值对梯度进行归一化weight_decay(float, 可选) – 权重衰减(L2 惩罚)(默认:0)
step(closure):进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50))
实现弹性反向传播算法。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictlr(float, 可选) – 学习率(默认:1e-2)etas(Tuple[float, float], 可选) – 一对(etaminus, etaplis),它们分别是乘法的增加和减小的因子(默认:0.5, 1.2)step_sizes(Tuple[float, float], 可选) – 允许的一对最小和最大的步长(默认:1e-6, 50)
step(closure):进行单次优化(参数更新)。
参数:
closure(callable) – 一个重新评价模型并返回 loss 的闭包,对于大多数参数来说是可选的
torch.optim.SGD(params, lr=<required>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
实现随机梯度下降算法。
参数:
params(iterable) – 待优化参数的 iterable 或者是定义了参数组的 dictlr(float) – 学习率momentum(float, 可选) – 动量因子(默认:0)weight_decay(float, 可选) – 权重衰减(L2 惩罚)(默认:0)dampening(float, 可选) – 动量的抑制因子(默认:0)nesterov(bool, 可选) – 使用 Nesterov 动量(默认:False)
示例:
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
optimizer.zero_grad()
loss_fn(model(input), target).backward()
optimizer.step()
26. CUDA 支持
torch.cuda.current_blas_handle()
返回 cublasHandle_t 指针,指向当前 cuBLAS 句柄。
torch.cuda.current_device()
返回当前所选设备的索引。
torch.cuda.current_stream()
返回一个当前所选的 Stream。
class torch.cuda.device(idx)
上下文管理器,可以更改所选设备。
参数:
idx(int) – 设备索引选择。如果这个参数是负的,则是无效操作
torch.cuda.device_count()
返回可得到的 GPU 数量。
class torch.cuda.device_of(obj)
将当前设备更改为给定对象的上下文管理器。可以使用张量和存储作为参数。如果给定的对象不是在 GPU 上分配的,这是一个无效操作。
参数:
obj(Tensor or Storage) – 在选定设备上分配的对象
torch.cuda.is_available()
返回一个 bool 值,指示 CUDA 当前是否可用。
torch.cuda.set_device(device)
设置当前设备。不鼓励使用此函数来设置。在大多数情况下,最好使用 CUDA_VISIBLE_DEVICES 环境变量。
参数:
device(int) – 所选设备。如果此参数为负,则此函数是无效操作
torch.cuda.stream(stream)
选择给定流的上下文管理器。在其上下文中排队的所有 CUDA 核心将在所选流上入队。
参数:
stream(Stream) – 所选流。如果是None,则这个管理器是无效的
torch.cuda.synchronize()
等待当前设备上所有流中的所有核心完成。
torch.cuda.comm.broadcast(tensor, devices)
向一些 GPU 广播张量。
参数:
tensor(Tensor) – 将要广播的张量devices(Iterable) – 一个可以广播的设备的迭代。注意,它的形式应该像(src, dst1, dst2, …),其第一个元素是广播来源的设备
返回:一个包含张量副本的元组,放置在与设备的索引相对应的设备上。
torch.cuda.comm.reduce_add(inputs, destination=None)
将来自多个 GPU 的张量相加。所有输入应具有匹配的形状。
参数:
inputs(Iterable[Tensor]) – 要相加张量的迭代destination(int, optional) – 将放置输出的设备(默认值:当前设备)
返回:一个包含放置在 destination 设备上的所有输入的元素总和的张量。
torch.cuda.comm.scatter(tensor, devices, chunk_sizes=None, dim=0, streams=None)
打散横跨多个 GPU 的张量。
参数:
tensor(Tensor) – 要分散的张量devices(Iterable[int]) – int 的迭代,指定哪些设备应该分散张量chunk_sizes(Iterable[int], optional) – 要放置在每个设备上的块大小。它应该匹配devices的长度并且总和为tensor.size(dim)。如果没有指定,张量将被分成相等的块dim(int, optional) – 沿着这个维度来 chunk 张量
返回:包含 tensor 块的元组,分布在给定的 devices 上。
torch.cuda.comm.gather(tensors, dim=0, destination=None)
从多个 GPU 收集张量。张量尺寸在不同于 dim 的所有维度上都应该匹配。
参数:
tensors(Iterable[Tensor]) – 要收集的张量的迭代dim(int) – 沿着此维度张量将被连接destination(int, optional) – 输出设备(-1表示 CPU,默认值:当前设备)
返回:一个张量位于 destination 设备上,这是沿着 dim 连接 tensors 的结果。
torch.cuda.Stream
CUDA 流的包装。
参数:
device(int, optional) – 分配流的设备priority(int, optional) – 流的优先级。较低的数字代表较高的优先级
方法:
query()– 检查所有提交的工作是否已经完成。返回一个布尔值,表示此流中的所有核心是否完成record_event(event=None)– 记录一个事件。参数event(Event, optional) – 要记录的事件。如果没有给出,将分配一个新的。返回记录的事件synchronize()– 等待此流中的所有核心完成wait_event(event)– 将所有未来的工作提交到流等待事件。参数event(Event) – 等待的事件wait_stream(stream)– 与另一个流同步。提交到此流的所有未来工作将等待直到所有核心在调用完成时提交给给定的流
torch.cuda.Event(enable_timing=False, blocking=False, interprocess=False, _handle=None)
CUDA 事件的包装。
参数:
enable_timing(bool) – 指示事件是否应该测量时间(默认值:False)blocking(bool) – 如果为true,wait()将被阻塞(默认值:False)interprocess(bool) – 如果为true,则可以在进程之间共享事件(默认值:False)
方法:
elapsed_time(end_event)– 返回事件记录之前经过的时间ipc_handle()– 返回此事件的 IPC 句柄query()– 检查事件是否已被记录。返回一个布尔值,指示事件是否已被记录record(stream=None)– 记录给定流的事件synchronize()– 与事件同步wait(stream=None)– 使给定的流等待事件
27. 模型创建
1. Sequential 线性模型
Sequential 模型适合构建线性堆叠的网络,即每一层的输出都是下一层的输入。这种模型非常适合初学者,并且对于大多数标准的深度学习任务来说已经足够了。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# 构造示例数据
X = torch.randn(100, 28 * 28) # 100个样本,每个样本28*28维
y = torch.randint(0, 10, (100,)) # 100个标签,每个标签是一个0到9的整数
# 创建数据集和数据加载器
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
# 使用nn.Sequential构建模型
model_sequential = nn.Sequential(
nn.Linear(28 * 28, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 10)
)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_sequential.parameters(), lr=0.01)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(dataloader):
# 前向传播
outputs = model_sequential(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 10 == 9: # 每10个batch打印一次
print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 10:.3f}')
running_loss = 0.0
2. ModuleList 非线性模型
ModuleList 中的子模块可以是任意类型的模块,而且可以是非连续的,即可以按需调用其中的模块。
import torch
import torch.nn as nn
class ModuleListModel(nn.Module):
def __init__(self):
super(ModuleListModel, self).__init__()
self.module_list = nn.ModuleList([
nn.Linear(10, 20),
nn.ReLU(),
nn.Linear(20, 10),
nn.ReLU()
])
def forward(self, x):
for module in self.module_list:
x = module(x)
return x
class SequentialModel(nn.Module):
def __init__(self):
super(SequentialModel, self).__init__()
self.sequential = nn.Sequential(
nn.Linear(10, 20),
nn.ReLU(),
nn.Linear(20, 10),
nn.ReLU()
)
def forward(self, x):
return self.sequential(x)
# 创建模型实例
module_list_model = ModuleListModel()
sequential_model = SequentialModel()
# 创建输入张量
input_tensor = torch.randn(1, 10)
# 使用 ModuleList 模型
output_module_list = module_list_model(input_tensor)
print("Output using ModuleList:", output_module_list)
# 使用 Sequential 模型
output_sequential = sequential_model(input_tensor)
print("Output using Sequential:", output_sequential)
3. 函数式 API (Functional API)
函数式 API 提供了一种更灵活的方式定义模型。它可以用来创建具有多个输入或输出、共享层、以及任意连接模式的复杂模型。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# 构造示例数据
X = torch.randn(100, 28 * 28) # 100个样本,每个样本28*28维
y = torch.randint(0, 10, (100,)) # 100个标签,每个标签是一个0到9的整数
# 创建数据集和数据加载器
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
class FunctionalModel(nn.Module):
def __init__(self):
super(FunctionalModel, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128)
self.fc2 = nn.Linear(128, 64)
self.fc3 = nn.Linear(64, 10)
def forward(self, x):
x = x.view(-1, 28 * 28) # 将输入拉平成一维
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
# 创建模型实例
model_functional = FunctionalModel()
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_functional.parameters(), lr=0.01)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(dataloader):
# 前向传播
outputs = model_functional(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 10 == 9: # 每10个batch打印一次
print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 10:.3f}')
running_loss = 0.0
4. 子类化 API (Subclassing API)
子类化 API 是另一种方式,通过继承 nn.Module 类来定义模型。这种方式提供了最大的灵活性,因为你可以在模型类的方法中直接编写自定义逻辑。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# 构造示例数据
X = torch.randn(100, 28 * 28) # 100个样本,每个样本28*28维
y = torch.randint(0, 10, (100,)) # 100个标签,每个标签是一个0到9的整数
# 创建数据集和数据加载器
dataset = TensorDataset(X, y)
dataloader = DataLoader(dataset, batch_size=10, shuffle=True)
class SubclassingModel(nn.Module):
def __init__(self):
super(SubclassingModel, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128)
self.fc2 = nn.Linear(128, 64)
self.fc3 = nn.Linear(64, 10)
def forward(self, x):
x = x.view(-1, 28 * 28) # 将输入拉平成一维
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
# 创建模型实例
model_subclassing = SubclassingModel()
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_subclassing.parameters(), lr=0.01)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(dataloader):
# 前向传播
outputs = model_subclassing(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 10 == 9: # 每10个batch打印一次
print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 10:.3f}')
running_loss = 0.0
28. 模型查看
1. 查看模型 summary
print(model)
2. 查看模型总参数数量
count = 0
for p in model.parameters():
# requires_grad表示是否根据梯度更新
if p.requires_grad:
count += p.numel()
print(count)
3. 查看模型各层参数数量
for name, param in model.named_parameters():
print(f"{name}:{param.size()}, Total params: {param.numel()}")
4. 查看模型各层详细信息
for name, child in model.named_children():
print(f"{name}:{child}")
29. 模型改进
1. 批量归一化 (Batch Normalization)
批量归一化通过对每一层的激活值进行归一化来稳定训练过程,减少内部协变量偏移问题。
改进的问题:
- 内部协变量偏移:随着训练的进行,前面层的分布变化会影响后面层的学习
- 加速训练:通过归一化输入,可以更快地收敛
示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import torchvision.transforms as transforms
import torchvision.datasets as datasets
# 构造示例数据
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=100, shuffle=True, num_workers=2)
testset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)
# 定义DNN模型
class DNNModelWithBN(nn.Module):
def __init__(self):
super(DNNModelWithBN, self).__init__()
self.fc1 = nn.Linear(28 * 28, 128)
self.bn1 = nn.BatchNorm1d(128)
self.fc2 = nn.Linear(128, 64)
self.bn2 = nn.BatchNorm1d(64)
self.fc3 = nn.Linear(64, 10)
def forward(self, x):
x = x.view(-1, 28 * 28) # 将输入拉平成一维
x = torch.relu(self.bn1(self.fc1(x))) # 添加批量归一化
x = torch.relu(self.bn2(self.fc2(x))) # 添加批量归一化
x = self.fc3(x)
return x
# 创建模型实例
model_with_bn = DNNModelWithBN()
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_with_bn.parameters(), lr=0.001, momentum=0.9)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(trainloader):
# 前向传播
outputs = model_with_bn(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 100 == 99: # 每100个batch打印一次
print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 100:.3f}')
running_loss = 0.0
# 评估模型
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = model_with_bn(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%')
2. 跳跃连接 (Skip Connections)
将网络中较早的层的输出直接传递给后续的层,有助于在网络的不同部分之间传递信息,这对于恢复细节非常重要。
改进的问题:
- 梯度消失:深层网络中梯度反向传播时容易消失
- 使网络更容易训练
示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import torchvision.transforms as transforms
import torchvision.datasets as datasets
# 构造示例数据
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=100, shuffle=True, num_workers=2)
testset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1, downsample=None):
super(ResidualBlock, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
self.downsample = downsample
self.stride = stride
def forward(self, x):
residual = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
if self.downsample:
residual = self.downsample(x)
out += residual
out = self.relu(out)
return out
class ResNet(nn.Module):
def __init__(self, block, layers, num_classes=10):
super(ResNet, self).__init__()
self.in_channels = 16
self.conv = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1, bias=False)
self.bn = nn.BatchNorm2d(16)
self.relu = nn.ReLU(inplace=True)
self.layer1 = self.make_layer(block, 16, layers[0])
self.layer2 = self.make_layer(block, 32, layers[1], 2)
self.layer3 = self.make_layer(block, 64, layers[2], 2)
self.avg_pool = nn.AvgPool2d(7)
self.fc = nn.Linear(64, num_classes)
def make_layer(self, block, out_channels, blocks, stride=1):
downsample = None
if (stride != 1) or (self.in_channels != out_channels):
downsample = nn.Sequential(
nn.Conv2d(self.in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(out_channels))
layers = []
layers.append(block(self.in_channels, out_channels, stride, downsample))
self.in_channels = out_channels
for _ in range(1, blocks):
layers.append(block(out_channels, out_channels))
return nn.Sequential(*layers)
def forward(self, x):
out = self.conv(x)
out = self.bn(out)
out = self.relu(out)
out = self.layer1(out)
out = self.layer2(out)
out = self.layer3(out)
out = self.avg_pool(out)
out = out.view(out.size(0), -1)
out = self.fc(out)
return out
# 创建模型实例
model_resnet = ResNet(ResidualBlock, [2, 2, 2])
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_resnet.parameters(), lr=0.001, momentum=0.9)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(trainloader):
# 前向传播
outputs = model_resnet(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 100 == 99: # 每100个batch打印一次
print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 100:.3f}')
running_loss = 0.0
# 评估模型
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = model_resnet(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%')
3. 残差连接 (Residual Connections)
跳跃连接的一种具体实现方式,残差连接通过添加跳跃连接来缓解深层网络中的梯度消失问题,并使网络更容易训练。
改进的问题:
- 梯度消失:深层网络中梯度反向传播时容易消失
- 更容易训练深层网络
示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import torchvision.transforms as transforms
import torchvision.datasets as datasets
# 构造示例数据
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=100, shuffle=True, num_workers=2)
testset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)
# 定义带有残差连接的基本块
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, in_planes, planes, stride=1):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
self.shortcut = nn.Sequential()
if stride != 1 or in_planes != self.expansion * planes:
self.shortcut = nn.Sequential(
nn.Conv2d(in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(self.expansion * planes)
)
def forward(self, x):
out = nn.functional.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.shortcut(x)
out = nn.functional.relu(out)
return out
# 定义ResNet模型
class ResNet(nn.Module):
def __init__(self, block, num_blocks, num_classes=10):
super(ResNet, self).__init__()
self.in_planes = 64
self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
self.linear = nn.Linear(512 * block.expansion, num_classes)
def _make_layer(self, block, planes, num_blocks, stride):
strides = [stride] + [1] * (num_blocks - 1)
layers = []
for stride in strides:
layers.append(block(self.in_planes, planes, stride))
self.in_planes = planes * block.expansion
return nn.Sequential(*layers)
def forward(self, x):
out = nn.functional.relu(self.bn1(self.conv1(x)))
out = self.layer1(out)
out = self.layer2(out)
out = self.layer3(out)
out = self.layer4(out)
out = nn.functional.avg_pool2d(out, 4)
out = out.view(out.size(0), -1)
out = self.linear(out)
return out
# 创建模型实例
model_resnet = ResNet(BasicBlock, [2, 2, 2, 2])
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model_resnet.parameters(), lr=0.001, momentum=0.9)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(trainloader):
# 前向传播
outputs = model_resnet(inputs)
# 计算损失
loss = criterion(outputs, labels)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 打印统计信息
running_loss += loss.item()
if i % 100 == 99: # 每100个batch打印一次
print(f'Epoch {epoch + 1}, Batch {i + 1}, Loss: {running_loss / 100:.3f}')
running_loss = 0.0
# 评估模型
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = model_resnet(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%')
4. 权重初始化 (Weight Initialization)
权重初始化方法(如 Xavier 初始化或 He 初始化)可以改善网络的收敛速度,避免梯度消失或爆炸。
改进的问题:
- 梯度消失或爆炸:随机初始化可能导致梯度消失或爆炸
- 更快的收敛速度
示例:对模型的不同部分应用不同的初始化方法
(1)随机初始化
- 均匀分布:
torch.nn.init.uniform_(tensor, a=-1, b=1) - 正态分布:
torch.nn.init.normal_(tensor, mean=0, std=1)
def init_weights_uniform(module):
if isinstance(module, nn.Linear) or isinstance(module, nn.Conv2d):
torch.nn.init.uniform_(module.weight, a=-0.05, b=0.05)
if module.bias is not None:
torch.nn.init.zeros_(module.bias)
def init_weights_normal(module):
if isinstance(module, nn.Linear) or isinstance(module, nn.Conv2d):
torch.nn.init.normal_(module.weight, mean=0, std=0.01)
if module.bias is not None:
torch.nn.init.zeros_(module.bias)
model.apply(init_weights_uniform) # 应用均匀分布初始化
# 或者
model.apply(init_weights_normal) # 应用正态分布初始化
(2)Xavier/Glorot 初始化
def init_weights_xavier(module):
if isinstance(module, nn.Linear) or isinstance(module, nn.Conv2d):
torch.nn.init.xavier_uniform_(module.weight)
if module.bias is not None:
torch.nn.init.zeros_(module.bias)
model.apply(init_weights_xavier) # 应用Xavier初始化
(3)He 初始化
def init_weights_he(module):
if isinstance(module, nn.Linear) or isinstance(module, nn.Conv2d):
torch.nn.init.kaiming_uniform_(module.weight, mode='fan_in', nonlinearity='relu')
if module.bias is not None:
torch.nn.init.zeros_(module.bias)
model.apply(init_weights_he) # 应用He初始化
5. 正则化 (Regularization)
正则化技术(如 L1、L2 或 Dropout)可以防止过拟合,提高模型的泛化能力。
改进的问题:
- 过拟合:模型在训练集上表现很好,但在测试集上表现不佳
- 泛化能力增强
示例:
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision.transforms as transforms
import torchvision.datasets as datasets
# 构造示例数据
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=100, shuffle=True, num_workers=2)
testset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)
# 辅助函数:L1正则化
def l1_regularizer(model, lambda_l1):
l1 = 0.0
for param in model.parameters():
l1 += torch.sum(torch.abs(param))
return lambda_l1 * l1
# 辅助函数:L2正则化
def l2_regularizer(model, lambda_l2):
l2 = 0.0
for param in model.parameters():
l2 += torch.sum(param ** 2)
return lambda_l2 * l2
# 定义网络模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(784, 128)
self.dropout = nn.Dropout(p=0.5) # p是丢弃的概率
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = x.view(-1, 784) # Flatten the input tensor
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = self.fc2(x)
return x
# 创建模型实例
model = Net()
# 设置正则化系数
lambda_l1 = 0.001
lambda_l2 = 0.001
# 使用优化器自带的weight_decay参数来实现L2正则化
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=lambda_l2)
# 定义损失函数
criterion = nn.CrossEntropyLoss()
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(trainloader):
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
# 添加L1正则化项
l1_reg = l1_regularizer(model, lambda_l1)
loss += l1_reg
# 注意:如果已经使用了优化器的weight_decay,则不需要手动添加L2正则化项
# loss += l2_regularizer(model, lambda_l2)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 100 == 99: # 每100个batch打印一次
print(f'Epoch {epoch+1}, Batch {i+1}, Loss: {running_loss / 100:.3f}')
running_loss = 0.0
# 评估模型
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%')
6. 数据增强 (Data Augmentation)
数据增强通过生成训练数据的多种变体来增加数据多样性,从而提高模型的鲁棒性和泛化能力。
改进的问题:
- 数据不足:少量数据可能导致模型过拟合
- 增强泛化能力
示例:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import torchvision.transforms as transforms
import torchvision.datasets as datasets
# 构造示例数据
transform = transforms.Compose([
# 随机水平翻转
transforms.RandomHorizontalFlip(),
# 随机旋转(角度范围为 -10 到 10 度)
transforms.RandomRotation(degrees=(-10, 10)),
# 随机裁剪,然后缩放为原图大小
transforms.RandomResizedCrop(size=(28, 28)),
# 颜色抖动
transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.1),
# 转换为张量
transforms.ToTensor(),
# 归一化
transforms.Normalize(mean=(0.5,), std=(0.5,))
])
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=100, shuffle=True, num_workers=2)
testset = datasets.MNIST(root='./data', train=False, download=True, transform=transforms.ToTensor())
testloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)
# 定义网络模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
self.bn1 = nn.BatchNorm2d(32)
self.relu = nn.ReLU()
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
self.bn2 = nn.BatchNorm2d(64)
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.fc1 = nn.Linear(64 * 14 * 14, 512)
self.fc2 = nn.Linear(512, 10)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.relu(x)
x = self.pool(x)
x = x.view(x.size(0), -1)
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
# 创建模型实例
model = Net()
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
running_loss = 0.0
for i, (inputs, labels) in enumerate(trainloader):
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 100 == 99: # 每100个batch打印一次
print(f'Epoch {epoch+1}, Batch {i+1}, Loss: {running_loss / 100:.3f}')
running_loss = 0.0
# 评估模型
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy of the network on the 10000 test images: {100 * correct / total:.2f}%')
30. 模型保存与加载
# 保存模型
torch.save(model.state_dict(), 'mnist_cnn.pth')
# 加载模型
model = Net()
model.load_state_dict(torch.load('mnist_cnn.pth'))
model.eval()
31. 分布式训练
1. 多机多卡(Multi-worker Multi-GPU)
每个机器上有一个或多个 GPU,使用 PyTorch 的分布式训练功能实现多机多卡并行训练。
示例:
# On each node, run the following command:
python -m torch.distributed.launch --nproc_per_node=4 train.py
train.py 脚本:
import torch.distributed as dist
import torch.multiprocessing as mp
def setup(rank, world_size):
dist.init_process_group(
backend='nccl',
init_method='env://',
world_size=world_size,
rank=rank
)
def cleanup():
dist.destroy_process_group()
def train(rank, world_size):
setup(rank, world_size)
model = Net().to(rank)
ddp_model = nn.parallel.DistributedDataParallel(model, device_ids=[rank])
# Training loop...
cleanup()
def main():
world_size = 4 # Number of GPUs per node times number of nodes
mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)
if __name__ == "__main__":
main()
2. 单机多卡(Single-worker Multi-GPU)
如果你在一个节点上有多个 GPU,可以使用 torch.nn.DataParallel 或 torch.nn.parallel.DistributedDataParallel 来实现多卡并行训练。
使用 DataParallel:
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = Net()
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
model = nn.DataParallel(model)
model.to(device)
**使用 DistributedDataParallel:**适用于更高级的分布式训练场景,需要设置分布式环境。
import os
import torch.distributed as dist
import torch.multiprocessing as mp
def setup(rank, world_size):
os.environ['MASTER_ADDR'] = 'localhost'
os.environ['MASTER_PORT'] = '12355'
# initialize the process group
dist.init_process_group("gloo", rank=rank, world_size=world_size)
def cleanup():
dist.destroy_process_group()
def train(rank, world_size):
setup(rank, world_size)
model = Net().to(rank)
ddp_model = nn.parallel.DistributedDataParallel(model, device_ids=[rank])
# Training loop...
cleanup()
def main():
world_size = torch.cuda.device_count()
mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)
if __name__ == "__main__":
main()
3. 单机单卡(Single-worker Single-GPU)
单机单卡是最简单的情况,只需要在定义模型时指定使用 GPU 设备即可。如果你的系统中有多个 GPU,可以指定使用哪一个 GPU。
示例:
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = Net().to(device)
4. 单机单 CPU
如果只使用 CPU 进行训练,可以简单地将模型放在 CPU 上。
示例:
device = torch.device("cpu")
model = Net().to(device)
5. 单机多 CPU
对于多 CPU 并行处理,可以使用 torch.multiprocessing 模块来启动多个进程。
示例:
import torch.multiprocessing as mp
def train(rank, world_size):
model = Net().to(rank)
# Training loop...
def main():
world_size = mp.cpu_count() # Use all available CPUs
mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)
if __name__ == "__main__":
main()
6. 多机多 CPU
在多机多 CPU 环境中进行分布式训练时,通常会采用消息传递接口(Message Passing Interface, MPI)或者类似的技术来协调各个机器之间的通信。PyTorch 提供了分布式训练的支持,可以使用 torch.distributed 模块来实现多机多 CPU 的分布式训练。
import os
import torch
import torch.distributed as dist
import torch.multiprocessing as mp
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
import torchvision.datasets as datasets
# 定义模型
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(784, 512)
self.fc2 = nn.Linear(512, 10)
def forward(self, x):
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
def train(rank, world_size):
# 初始化分布式环境
os.environ['MASTER_ADDR'] = 'master_address' # 主节点地址
os.environ['MASTER_PORT'] = '12355' # 主节点端口
dist.init_process_group("gloo", rank=rank, world_size=world_size)
# 创建模型实例
model = Net()
model = model.to(rank)
ddp_model = nn.parallel.DistributedDataParallel(model, device_ids=[rank])
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(ddp_model.parameters(), lr=0.001)
# 准备数据
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
trainset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_sampler = torch.utils.data.distributed.DistributedSampler(trainset, num_replicas=world_size, rank=rank)
trainloader = DataLoader(trainset, batch_size=100, shuffle=False, sampler=train_sampler, num_workers=2)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
train_sampler.set_epoch(epoch)
running_loss = 0.0
for i, (inputs, labels) in enumerate(trainloader):
# 将输入数据转换为平坦的一维向量
inputs = inputs.view(inputs.size(0), -1)
optimizer.zero_grad()
outputs = ddp_model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 100 == 99: # 每100个batch打印一次
print(f'Process {rank}: Epoch {epoch+1}, Batch {i+1}, Loss: {running_loss / 100:.3f}')
running_loss = 0.0
# 清理分布式环境
dist.destroy_process_group()
def main(world_size):
# 启动多进程
mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)
if __name__ == "__main__":
world_size = 4 # 假设共有4台机器
main(world_size)
32. 深度学习推荐算法
深度学习推荐系统是利用深度学习技术来进行个性化推荐的一种方法。这些模型旨在捕捉用户的行为模式和偏好,以便预测用户可能感兴趣的内容。以下是几种常用的深度学习推荐模型:
1. 双塔模型(Two-Tower Model)
双塔模型是推荐系统中经典的深度学习架构,由用户塔(User Tower)和物品塔(Item Tower)组成,分别对用户特征和物品特征进行向量化表示,通过计算两者的内积来预测用户对物品的偏好。
示例代码:
import torch
import torch.nn as nn
import torch.nn.functional as F
# 用户行为数据
# 假设用户行为数据为用户浏览过的商品ID列表
user_behavior_data = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]
]
# 用户属性数据
# 假设用户属性数据为年龄、性别、职业
user_attribute_data = [
[25, 0, 1], # 年龄25岁,性别男,职业工程师
[30, 1, 2], # 年龄30岁,性别女,职业医生
[28, 0, 3], # 年龄28岁,性别男,职业教师
[32, 1, 4] # 年龄32岁,性别女,职业律师
]
# 物品特征数据
# 假设物品特征数据为类别、价格、品牌
item_feature_data = [
[1, 100, 'BrandA'],
[2, 200, 'BrandB'],
[3, 300, 'BrandC'],
[4, 400, 'BrandD'],
[5, 500, 'BrandE'],
[6, 600, 'BrandF'],
[7, 700, 'BrandG'],
[8, 800, 'BrandH'],
[9, 900, 'BrandI'],
[10, 1000, 'BrandJ'],
[11, 1100, 'BrandK'],
[12, 1200, 'BrandL']
]
# 将用户行为数据转换为用户-物品交互矩阵
num_users = len(user_behavior_data)
num_items = len(item_feature_data)
user_item_matrix = torch.zeros((num_users, num_items))
for i, behavior in enumerate(user_behavior_data):
for item_id in behavior:
user_item_matrix[i][item_id - 1] = 1
# 将用户属性数据转换为张量
user_attribute_tensor = torch.tensor(user_attribute_data, dtype=torch.float32)
# 将物品特征数据转换为张量
item_feature_tensor = torch.tensor([[int(i), int(p), ord(b[0])] for i, p, b in item_feature_data], dtype=torch.float32)
class UserTower(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super(UserTower, self).__init__()
self.linear1 = nn.Linear(input_dim, hidden_dim)
self.linear2 = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
x = F.relu(self.linear1(x))
x = self.linear2(x)
return x
class ItemTower(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super(ItemTower, self).__init__()
self.linear1 = nn.Linear(input_dim, hidden_dim)
self.linear2 = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
x = F.relu(self.linear1(x))
x = self.linear2(x)
return x
class TwoTowerModel(nn.Module):
def __init__(self, user_input_dim, user_hidden_dim, user_output_dim, item_input_dim, item_hidden_dim, item_output_dim):
super(TwoTowerModel, self).__init__()
self.user_tower = UserTower(user_input_dim, user_hidden_dim, user_output_dim)
self.item_tower = ItemTower(item_input_dim, item_hidden_dim, item_output_dim)
def forward(self, user_input, item_input):
user_output = self.user_tower(user_input)
item_output = self.item_tower(item_input)
return torch.matmul(user_output, item_output.t())
# 模型初始化
user_input_dim = user_attribute_tensor.shape[1]
item_input_dim = item_feature_tensor.shape[1]
user_hidden_dim = 64
item_hidden_dim = 64
user_output_dim = 32
item_output_dim = 32
model = TwoTowerModel(user_input_dim, user_hidden_dim, user_output_dim, item_input_dim, item_hidden_dim, item_output_dim)
# 损失函数和优化器
criterion = nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 假设标签数据为用户对物品的兴趣程度(1表示感兴趣,0表示不感兴趣)
labels = torch.tensor([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=torch.float32)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
optimizer.zero_grad()
outputs = model(user_attribute_tensor, item_feature_tensor)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
# 测试模型
with torch.no_grad():
outputs = model(user_attribute_tensor, item_feature_tensor)
_, predicted = torch.max(outputs.data, 1)
print("Predicted items:", predicted)
2. Wide & Deep Learning Model
Wide & Deep Learning 模型结合了线性模型(Wide 部分)与非线性深层神经网络(Deep 部分),能够同时从数据中学习低阶和高阶的特征交互。
a. 模型特性
- 灵活性:Wide 部分通常包含线性模型(如逻辑回归),可以处理大量的稀疏特征,捕捉特征之间的第一阶关系。Deep 部分使用深度神经网络来建模特征之间的高阶交互。
- 强大的表达能力:深度神经网络可以通过多层非线性变换捕捉复杂的数据分布,而线性模型则可以处理高维稀疏数据。
- 易于扩展:Wide 部分可以很容易地扩展到包含大量的特征,尤其是对于稀疏特征。Deep 部分可以通过增加层数和节点数来扩展模型的容量。
- 可解释性与泛化能力:Wide 部分保留了一定程度的可解释性,因为它类似于传统的线性模型。Deep 部分能够更好地泛化到未见过的数据,因为它能够捕捉到数据中的复杂模式。
b. 设计思路
- 捕捉低阶和高阶特征组合:在许多现实世界的应用中,数据往往包含了大量的低阶特征(如用户性别、年龄等)和高阶特征(如用户的兴趣爱好)。Wide 部分能够有效地处理低阶特征,而 Deep 部分则擅长捕捉高阶特征之间的复杂关系。
- 平衡性能与可解释性:对于某些应用场景而言,模型的可解释性是非常重要的。Wide 部分提供了一种透明的方式来看待模型是如何做出决策的,而 Deep 部分则可以提供更高的预测精度。
- 处理稀疏数据:推荐系统中的数据通常是高度稀疏的,Wide 部分能够很好地处理这种稀疏性,而 Deep 部分则能够通过嵌入(Embedding)等技术来减少稀疏特征的维度,从而更好地捕捉潜在的模式。
- 提升模型性能:实践证明,Wide & Deep 模型在很多任务上都比单独使用 Wide 或 Deep 模型表现得更好。这是因为它们结合了两者的优点,从而能够在不同类型的特征上表现出色。
c. 示例代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
# 构造数据
np.random.seed(0) # 设置随机种子,确保结果可复现
# 数值特征
numeric_features = np.random.rand(100, 3) # 100 个样本,每个样本 3 个数值特征
# 类别特征
categorical_features = np.random.choice(['A', 'B', 'C'], size=(100, 2)) # 100 个样本,每个样本 2 个类别特征
# 将类别特征编码为 one-hot 编码
one_hot_features = np.zeros((100, 2 * 3)) # 2 个类别特征,每个类别特征有 3 种可能的值
for i in range(100):
for j in range(2):
one_hot_features[i, j * 3 + ord(categorical_features[i, j]) - ord('A')] = 1
# 标签
labels = np.random.randint(2, size=100) # 二分类标签
# 转换为 PyTorch 张量
numeric_tensor = torch.tensor(numeric_features, dtype=torch.float32)
one_hot_tensor = torch.tensor(one_hot_features, dtype=torch.float32)
label_tensor = torch.tensor(labels, dtype=torch.float32)
# 定义 Wide & Deep Learning 模型
class WideDeepModel(nn.Module):
def __init__(self, numeric_input_dim, one_hot_input_dim, hidden_dim, output_dim):
super(WideDeepModel, self).__init__()
# Wide 部分
self.linear = nn.Linear(numeric_input_dim + one_hot_input_dim, output_dim)
# Deep 部分
self.deep_layers = nn.Sequential(
nn.Linear(numeric_input_dim + one_hot_input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim // 2),
nn.ReLU(),
nn.Linear(hidden_dim // 2, output_dim),
)
def forward(self, numeric_input, one_hot_input):
# Wide 部分
wide_part = torch.cat((numeric_input, one_hot_input), dim=1)
wide_output = self.linear(wide_part)
# Deep 部分
deep_part = torch.cat((numeric_input, one_hot_input), dim=1)
deep_output = self.deep_layers(deep_part)
# 结合 Wide 和 Deep 部分
combined_output = wide_output + deep_output
return combined_output
# 创建模型实例
numeric_input_dim = numeric_tensor.shape[1]
one_hot_input_dim = one_hot_tensor.shape[1]
hidden_dim = 64
output_dim = 1
model = WideDeepModel(numeric_input_dim, one_hot_input_dim, hidden_dim, output_dim)
# 定义损失函数和优化器
criterion = nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
optimizer.zero_grad()
outputs = model(numeric_tensor, one_hot_tensor)
loss = criterion(outputs.squeeze(), label_tensor)
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 测试模型
with torch.no_grad():
test_outputs = model(numeric_tensor, one_hot_tensor)
predicted_labels = (test_outputs > 0).float().squeeze()
accuracy = (predicted_labels == label_tensor).sum().item() / len(label_tensor)
print(f'Test Accuracy: {accuracy:.4f}')
3. DeepFM (Deep Factorization Machine)
DeepFM 同时具备因子分解机(Factorization Machine, FM)的第一阶和第二阶特征组合的能力,并结合深层神经网络来建模高阶特征组合。
a. 模型特点
- Factorization Machine (FM):FM 是一种二阶特征交互模型,能够捕捉特征之间的两两交互。FM 能够处理稀疏特征,并且对于每个特征,它通过嵌入向量来表示。
- Deep Neural Network (DNN):DNN 部分可以捕捉高阶特征交互,通过多层非线性变换来学习特征之间的复杂关系。DNN 能够处理非线性关系,并且通过堆叠多层来增强模型的表达能力。
- 结合两者的优势:DeepFM 模型结合了 FM 和 DNN 的优势,既能够捕捉低阶特征交互(通过 FM),又能够捕捉高阶特征交互(通过 DNN)。输出层将 FM 和 DNN 的部分融合在一起,共同进行预测。
b. 设计思路
DeepFM 模型的设计思路是为了在推荐系统等场景下更有效地捕捉特征之间的交互作用,特别是在处理大规模稀疏数据时。它结合了因子分解机(Factorization Machine, FM)的强大交互能力和深度神经网络(Deep Neural Network, DNN)的非线性拟合能力。以下是 DeepFM 设计的主要思路:
因子分解机(FM):FM 是一种统计学习模型,特别适用于稀疏数据,它能有效地估计特征间的相互作用。FM 的一个关键点在于它能够显式地建模所有成对特征之间的交互作用,并且能够通过学习得到的嵌入向量(embedding vectors)来表示这些交互。
FM 的优点:
- 线性部分:能够捕捉特征本身的贡献。
- 二阶交互部分:能够捕捉特征之间的两两交互作用,这对于很多推荐系统中的任务非常重要,因为用户的偏好往往是由不同特征的组合决定的。
- 参数高效性:即使在特征空间非常大的情况下,由于只考虑二阶交互,参数数量也是可控的。
深度神经网络(DNN):DNN 能够通过多层非线性变换来学习特征之间的复杂关系。与传统的机器学习方法相比,DNN 可以自动地从原始数据中提取高级抽象特征,并且能够处理更高阶的特征交互。
DNN 的优点:
- 强大的非线性拟合能力:能够学习到复杂的模式和特征间的高阶交互。
- 自动特征学习:不需要手动设计特征,网络自己会学习到有助于任务完成的特征表示。
- 灵活性:可以通过增加或减少网络层数来调整模型的复杂度。
DeepFM 的结合:DeepFM 模型将 FM 和 DNN 的优点结合起来,通过两个分支分别处理低阶和高阶特征交互,并最终将它们融合在一个输出层中。
DeepFM 的设计思路:
- 并行学习:FM 部分负责学习特征之间的二阶交互,而 DNN 部分则学习高阶交互。
- 互补优势:FM 能够有效捕捉到特征之间的显式交互,而 DNN 则可以捕捉到隐式的、复杂的交互。
- 共享输入:两者都基于相同的输入特征,但通过不同的机制来提取特征的重要性。
- 融合输出:最后,FM 和 DNN 的输出被融合在一起,共同决定最终的预测结果,这样可以充分利用两种模型的优点。
DeepFM 的设计思想是通过利用 FM 来捕捉特征之间明确的、低阶的交互作用,同时利用 DNN 来捕捉那些更高阶、更复杂的交互作用。这样的设计使得模型能够在保持较高的解释性和相对较低的复杂度的同时,还能处理非常复杂的特征交互问题。这使得 DeepFM 在推荐系统、广告点击率预测等任务上表现得非常好。
c. 示例代码
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
from torch.utils.data import Dataset, DataLoader
# 设置随机种子以确保结果的可重复性
np.random.seed(42)
torch.manual_seed(42)
# 生成示例数据
num_users = 1000
num_items = 500
num_features = 10
max_age = 100
# 生成用户ID、项目ID、年龄、其他特征及标签等数据
user_ids = np.random.randint(0, num_users, size=(num_users * num_items))
item_ids = np.random.randint(0, num_items, size=(num_users * num_items))
ages = np.random.randint(18, max_age, size=(num_users * num_items))
features = np.random.randint(0, 2, size=(num_users * num_items, num_features))
labels = np.random.randint(0, 2, size=(num_users * num_items))
# 创建PyTorch Dataset
class CustomDataset(Dataset):
def __init__(self, user_ids, item_ids, ages, features, labels):
self.user_ids = torch.tensor(user_ids, dtype=torch.long)
self.item_ids = torch.tensor(item_ids, dtype=torch.long)
self.ages = torch.tensor(ages, dtype=torch.float32).reshape(-1, 1)
self.features = torch.tensor(features, dtype=torch.float32)
self.labels = torch.tensor(labels, dtype=torch.float32)
def __len__(self):
return len(self.user_ids)
def __getitem__(self, idx):
return self.user_ids[idx], self.item_ids[idx], self.ages[idx], self.features[idx], self.labels[idx]
# 创建数据集
dataset = CustomDataset(user_ids, item_ids, ages, features, labels)
# 构建数据加载器
data_loader = DataLoader(dataset, batch_size=32, shuffle=True)
# 定义 DeepFM 模型
class DeepFM(nn.Module):
def __init__(self, num_users, num_items, embedding_dim, num_features):
super(DeepFM, self).__init__()
self.embedding_dim = embedding_dim
self.num_features = num_features
# FM 第一阶部分
self.linear = nn.Linear(num_features + embedding_dim * 2 + 1, 1)
# FM 第二阶部分
self.user_embedding = nn.Embedding(num_users + 1, embedding_dim)
self.item_embedding = nn.Embedding(num_items + 1, embedding_dim)
self.user_embedding.weight.data.normal_(0, 0.01)
self.item_embedding.weight.data.normal_(0, 0.01)
# DNN 部分
self.dnn_layers = nn.Sequential(
nn.Linear(num_features + embedding_dim * 2 + 1, 64),
nn.ReLU(),
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, 1)
)
def forward(self, user_id, item_id, age, features):
# FM 第一阶部分
user_embed = self.user_embedding(user_id).view(-1, self.embedding_dim)
item_embed = self.item_embedding(item_id).view(-1, self.embedding_dim)
linear_part = self.linear(torch.cat([features, user_embed, item_embed, age], dim=1))
# FM 第二阶部分
embed_inputs = torch.cat([user_embed.unsqueeze(1), item_embed.unsqueeze(1)], dim=1)
square_of_sum = torch.sum(embed_inputs, dim=1) ** 2
sum_of_square = torch.sum(embed_inputs ** 2, dim=1)
fm_part = 0.5 * torch.sum(square_of_sum - sum_of_square, dim=1, keepdim=True)
# DNN 部分
dnn_part = self.dnn_layers(torch.cat([features, user_embed, item_embed, age], dim=1))
# 结合 FM 和 DNN 部分
total_output = linear_part + fm_part + dnn_part
return total_output
# 创建模型实例
embedding_dim = 8
model = DeepFM(num_users, num_items, embedding_dim, num_features)
# 定义损失函数和优化器
criterion = nn.BCEWithLogitsLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
for batch_idx, (user_id, item_id, age, features, labels) in enumerate(data_loader):
optimizer.zero_grad()
outputs = model(user_id, item_id, age, features)
loss = criterion(outputs.squeeze(), labels.float())
loss.backward()
optimizer.step()
if (epoch + 1) % 1 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 测试模型
with torch.no_grad():
test_outputs = []
test_labels = []
for user_id, item_id, age, features, labels in data_loader:
outputs = model(user_id, item_id, age, features)
test_outputs.append(outputs)
test_labels.append(labels)
test_outputs = torch.cat(test_outputs).squeeze()
test_labels = torch.cat(test_labels)
predicted_labels = (test_outputs > 0).float()
accuracy = (predicted_labels == test_labels).sum().item() / len(test_labels)
print(f'Test Accuracy: {accuracy:.4f}')
4. Neural Collaborative Filtering (NCF)
NCF 使用多层感知机(MLP)来模拟用户-项目之间的相互作用,从而实现协同过滤的效果。
a. 模型特性
- 深度学习模型:NCF 采用深度神经网络来学习用户和物品的潜在表示。
- 协同过滤:通过学习用户-物品之间的历史交互数据来预测用户对未见过的物品的兴趣。
- 非线性映射:利用多层神经网络来捕捉用户和物品之间复杂的非线性关系。
- 灵活的架构:可以很容易地扩展模型的深度和宽度,以适应不同的任务需求。
b. 设计思路
- 用户和物品嵌入:首先将用户和物品的 ID 通过嵌入层(Embedding Layer)映射到一个低维的稠密向量空间。
- 多层神经网络:通过多层全连接网络(Fully Connected Layers)来学习用户和物品的潜在表示,并捕捉它们之间的交互关系。
- 输出层:最终通过一个输出层来预测用户对物品的评分或点击概率。
c. 示例代码
import numpy as np
import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import torch.optim as optim
# 设置随机种子以确保结果的可重复性
np.random.seed(42)
torch.manual_seed(42)
# 生成示例数据
num_users = 1000
num_items = 500
num_interactions = num_users * num_items
# 生成用户ID、物品ID和评分
user_ids = np.random.randint(0, num_users, size=num_interactions)
item_ids = np.random.randint(0, num_items, size=num_interactions)
ratings = np.random.randint(1, 6, size=num_interactions)
# 创建DataFrame
data = pd.DataFrame({
'user_id': user_ids,
'item_id': item_ids,
'rating': ratings
})
# 显示数据样本
print(data.head())
# 分离特征并转换为Tensor
users = torch.tensor(data['user_id'].values, dtype=torch.long)
items = torch.tensor(data['item_id'].values, dtype=torch.long)
ratings = torch.tensor(data['rating'].values, dtype=torch.float).view(-1, 1)
# 定义数据集类
class RatingDataset(Dataset):
def __init__(self, users, items, ratings):
self.users = users
self.items = items
self.ratings = ratings
def __len__(self):
return len(self.users)
def __getitem__(self, idx):
return self.users[idx], self.items[idx], self.ratings[idx]
dataset = RatingDataset(users, items, ratings)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 定义模型
class NCFModel(nn.Module):
def __init__(self, num_users, num_items, embedding_dim):
super(NCFModel, self).__init__()
self.user_embedding = nn.Embedding(num_users, embedding_dim)
self.item_embedding = nn.Embedding(num_items, embedding_dim)
self.fc1 = nn.Linear(embedding_dim * 2, 64)
self.fc2 = nn.Linear(64, 32)
self.output_layer = nn.Linear(32, 1)
def forward(self, user, item):
user_emb = self.user_embedding(user)
item_emb = self.item_embedding(item)
concatenated = torch.cat([user_emb, item_emb], dim=1)
fc1_out = self.fc1(concatenated)
fc2_out = self.fc2(fc1_out)
output = self.output_layer(fc2_out)
return output
# 实例化模型
embedding_dim = 8
model = NCFModel(num_users, num_items, embedding_dim)
# 损失函数和优化器
loss_fn = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
for user, item, rating in dataloader:
prediction = model(user, item)
loss = loss_fn(prediction, rating)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 查看模型结构
print(model)
5. Matrix Factorization with MLP (MF-MLP)
MF-MLP 类似于 NCF,但更专注于使用神经网络来替代传统的矩阵分解方法。
a. 模型特性
- 矩阵分解:通过分解用户-物品评分矩阵来得到用户的偏好和物品的属性。
- 多层感知机:通过多个隐藏层的神经网络来学习用户和物品之间的非线性关系。
- 融合模型:将 MF 和 MLP 的结果融合起来,以获得更好的预测效果。
b. 设计思路
- 用户和物品嵌入:与 NCF 类似,首先将用户和物品 ID 映射到低维向量空间。
- 矩阵分解部分:通过简单的内积操作来估计用户对物品的评分。
- MLP 部分:将用户和物品的嵌入向量拼接后输入到 MLP 中,通过多层全连接网络来学习更复杂的交互模式。
- 结果融合:将 MF 部分和 MLP 部分的结果加权融合,得到最终的预测评分。
c. 示例代码
import numpy as np
import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader
import torch.nn as nn
import torch.optim as optim
# 设置随机种子以确保结果的可重复性
np.random.seed(42)
torch.manual_seed(42)
# 生成示例数据
num_users = 1000
num_items = 500
num_interactions = num_users * num_items
# 生成用户ID、物品ID和评分
user_ids = np.random.randint(0, num_users, size=num_interactions)
item_ids = np.random.randint(0, num_items, size=num_interactions)
ratings = np.random.randint(1, 6, size=num_interactions)
# 创建DataFrame
data = pd.DataFrame({
'user_id': user_ids,
'item_id': item_ids,
'rating': ratings
})
# 显示数据样本
print(data.head())
# 分离特征并转换为Tensor
users = torch.tensor(data['user_id'].values, dtype=torch.long)
items = torch.tensor(data['item_id'].values, dtype=torch.long)
ratings = torch.tensor(data['rating'].values, dtype=torch.float).view(-1, 1)
# 定义数据集类
class RatingDataset(Dataset):
def __init__(self, users, items, ratings):
self.users = users
self.items = items
self.ratings = ratings
def __len__(self):
return len(self.users)
def __getitem__(self, idx):
return self.users[idx], self.items[idx], self.ratings[idx]
dataset = RatingDataset(users, items, ratings)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 定义模型
class MFMLPModel(nn.Module):
def __init__(self, num_users, num_items, embedding_dim):
super(MFMLPModel, self).__init__()
self.user_embedding = nn.Embedding(num_users, embedding_dim)
self.item_embedding = nn.Embedding(num_items, embedding_dim)
# MF 部分
self.mf_output = MultiplyLayer()
# MLP 部分
self.mlp_concat = ConcatenateLayer()
self.mlp_fc1 = nn.Linear(embedding_dim * 2, 64)
self.mlp_fc2 = nn.Linear(64, 32)
self.mlp_output = nn.Linear(32, 1)
# 结果融合
self.combined_output = AddLayer()
def forward(self, user, item):
user_emb = self.user_embedding(user)
item_emb = self.item_embedding(item)
mf_output = self.mf_output(user_emb, item_emb)
mlp_concat = self.mlp_concat(user_emb, item_emb)
mlp_fc1_out = self.mlp_fc1(mlp_concat)
mlp_fc1_out = torch.relu(mlp_fc1_out)
mlp_fc2_out = self.mlp_fc2(mlp_fc1_out)
mlp_fc2_out = torch.relu(mlp_fc2_out)
mlp_output = self.mlp_output(mlp_fc2_out)
combined_output = self.combined_output(mf_output, mlp_output)
return combined_output
# 自定义层
class MultiplyLayer(nn.Module):
def forward(self, x, y):
return torch.mul(x, y)
class ConcatenateLayer(nn.Module):
def forward(self, x, y):
return torch.cat((x, y), dim=1)
class AddLayer(nn.Module):
def forward(self, x, y):
return x + y
# 实例化模型
embedding_dim = 8
model = MFMLPModel(num_users, num_items, embedding_dim)
# 损失函数和优化器
loss_fn = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
for user, item, rating in dataloader:
prediction = model(user, item)
loss = loss_fn(prediction, rating)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 查看模型结构
print(model)
6. Deep Cross Network (DCN)
DCN 将交叉网络(Cross Network)与深度神经网络相结合,其中交叉网络专门用于显式地建模特征间的高阶交互。
a. 模型特性
- 深度网络(DNN):用于学习特征的复杂组合。
- 交叉网络(Cross Network):专门设计用来学习特征间的交互作用。
- 双轨学习:通过并行使用 DNN 和交叉网络,模型能够同时从线性组合和特征交互中学习。
- 高效性:相比于纯深度模型,DCN 能够更有效地利用计算资源。
b. 设计思路
- 交叉网络:通过一系列的权重矩阵和偏置项来模拟多项式特征的交叉。每一层的输出都是前一层输出与输入特征的加权和加上一个偏置项。
- 深度网络:类似于普通的深层神经网络,用于捕捉特征间复杂的非线性关系。
- 融合输出:最终的预测是通过将交叉网络和深度网络的输出连接起来,再经过全连接层得到的。
c. 示例代码
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
# 设置随机种子以确保结果的可重复性
np.random.seed(42)
torch.manual_seed(42)
# 随机生成一些数据
num_samples = 1000
num_features = 10
features = {f'feature_{i}': np.random.rand(num_samples) for i in range(num_features)}
labels = {'click': np.random.randint(0, 2, size=num_samples)}
data = pd.DataFrame({**features, **labels})
# 显示数据样本
print(data.head())
# 转换为Tensor
X_train = torch.tensor(data.drop('click', axis=1).values, dtype=torch.float32)
y_train = torch.tensor(data['click'].values, dtype=torch.float32).view(-1, 1)
# 使用PyTorch DataLoader来处理数据
dataset = TensorDataset(X_train, y_train)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 自定义Cross Layer
class CrossLayer(nn.Module):
def __init__(self, feature_dim, l2_reg=0.0):
super(CrossLayer, self).__init__()
self.feature_dim = feature_dim
self.kernel = nn.Parameter(torch.randn(feature_dim, 1) * 1e-4)
self.bias = nn.Parameter(torch.zeros(feature_dim))
if l2_reg > 0.0:
self.regularizer = lambda: l2_reg * torch.sum(self.kernel ** 2)
else:
self.regularizer = lambda: 0.0
def forward(self, x_0, x):
return x_0 * (torch.matmul(x, self.kernel) + 1) + self.bias + x
# 定义DCN模型
class DCNModel(nn.Module):
def __init__(self, feature_dim, cross_num, dnn_hidden_units, l2_reg_cross=0.0, l2_reg_dnn=0.0):
super(DCNModel, self).__init__()
self.cross_layers = nn.ModuleList([CrossLayer(feature_dim, l2_reg_cross) for _ in range(cross_num)])
self.dnn_layers = nn.ModuleList()
prev_dim = feature_dim
for hidden_unit in dnn_hidden_units:
self.dnn_layers.append(nn.Linear(prev_dim, hidden_unit))
prev_dim = hidden_unit
self.final_layer = nn.Linear(prev_dim + feature_dim, 1)
self.sigmoid = nn.Sigmoid()
self.l2_reg_dnn = l2_reg_dnn
def forward(self, x):
x_0 = x
x = x
# Cross Network
for cross_layer in self.cross_layers:
x = cross_layer(x_0, x)
# DNN
for dnn_layer in self.dnn_layers:
x = torch.relu(dnn_layer(x))
# Combine and Output
x = torch.cat([x, x_0], dim=1)
output = self.sigmoid(self.final_layer(x))
return output
# 模型参数
feature_dim = num_features
cross_num = 2
dnn_hidden_units = [128, 64]
# 构建模型
dcn_model = DCNModel(feature_dim, cross_num, dnn_hidden_units)
# 损失函数和优化器
loss_fn = nn.BCELoss()
optimizer = optim.Adam(dcn_model.parameters(), lr=0.001)
# 训练模型
num_epochs = 5
for epoch in range(num_epochs):
for X_batch, y_batch in dataloader:
prediction = dcn_model(X_batch)
loss = loss_fn(prediction, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 查看模型结构
print(dcn_model)
7. Factorization-supported Neural Networks (FNN)
FNN 在输入到神经网络之前先进行因子分解,以增强模型的学习能力。
a. 模型特性
- 因子分解:通过因子分解技术来提取用户和项目的低维表示(即嵌入向量),这些向量能够捕获每个用户和项目的基本属性。
- 神经网络:利用神经网络来学习更复杂的非线性特征组合,从而提高模型的预测准确性。
- 减少过拟合:通过引入正则化项和使用 dropout 等技术来避免过拟合问题。
- 可扩展性:模型可以很容易地扩展到大规模数据集上。
b. 设计思路
- 嵌入层:为每个用户和项目分配一个低维向量表示,通常通过查找表的方式实现。
- 交叉特征:通过计算嵌入向量之间的元素乘积来创建交叉特征,这有助于捕捉用户和项目之间隐含的相互作用。
- 全连接层:将嵌入向量及其交叉特征连接起来,通过多层全连接神经网络来学习高级抽象特征。
- 输出层:最终的输出层通常是单个节点,用于预测评分或点击率等目标变量。
c. 示例代码
import numpy as np
import pandas as pd
import torch
from torch.utils.data import TensorDataset, DataLoader
import torch.nn as nn
import torch.optim as optim
# 设置随机种子以确保结果的可重复性
np.random.seed(42)
torch.manual_seed(42)
# 随机生成一些数据
num_users = 100
num_items = 50
num_interactions = 1000
user_ids = np.random.choice(num_users, size=num_interactions)
item_ids = np.random.choice(num_items, size=num_interactions)
ratings = np.random.randint(1, 6, size=num_interactions)
data = pd.DataFrame({
'user_id': user_ids,
'item_id': item_ids,
'rating': ratings
})
# 显示数据样本
print(data.head())
# 转换为Tensor
users = torch.tensor(data['user_id'].values, dtype=torch.long)
items = torch.tensor(data['item_id'].values, dtype=torch.long)
ratings = torch.tensor(data['rating'].values, dtype=torch.float).view(-1, 1)
# 使用PyTorch DataLoader来处理数据
dataset = TensorDataset(users, items, ratings)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 自定义模型
class FNNModel(nn.Module):
def __init__(self, num_users, num_items, embedding_dim):
super(FNNModel, self).__init__()
self.user_embedding = nn.Embedding(num_users, embedding_dim)
self.item_embedding = nn.Embedding(num_items, embedding_dim)
self.fc1 = nn.Linear(embedding_dim * 3, 64)
self.fc2 = nn.Linear(64, 32)
self.output_layer = nn.Linear(32, 1)
def forward(self, user, item):
user_emb = self.user_embedding(user)
item_emb = self.item_embedding(item)
user_vec = user_emb.squeeze()
item_vec = item_emb.squeeze()
# 交叉特征
crossed_features = torch.mul(user_vec, item_vec)
# 拼接原始特征与交叉特征
concatenated_features = torch.cat([user_vec, item_vec, crossed_features], dim=1)
# 全连接层
hidden_layer_1 = torch.relu(self.fc1(concatenated_features))
hidden_layer_2 = torch.relu(self.fc2(hidden_layer_1))
output = self.output_layer(hidden_layer_2)
return output
# 模型参数
embedding_dim = 8
# 构建模型
fnn_model = FNNModel(num_users, num_items, embedding_dim)
# 损失函数和优化器
loss_fn = nn.MSELoss()
optimizer = optim.Adam(fnn_model.parameters(), lr=0.001)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
for user, item, rating in dataloader:
prediction = fnn_model(user, item)
loss = loss_fn(prediction, rating)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 查看模型结构
print(fnn_model)
8. AutoInt (Automatic Integration)
AutoInt 利用自注意力机制(Self-Attention Mechanism)自动学习特征间的关系,适用于稀疏数据场景。
a. 模型特点
- 自动特征交互:AutoInt 模型能够自动地识别和学习特征之间的复杂交互,而不需要人工选择交互项。
- 自注意力机制:利用自注意力机制(Self-Attention Mechanism),AutoInt 可以有效地捕捉不同特征之间的依赖关系。
- 灵活性:该模型可以轻松地与其他类型的特征工程方法相结合,提高模型的整体性能。
b. 设计思路
- 特征嵌入:将原始的稀疏特征(如用户ID、物品ID等)转换成密集的低维向量。
- 自注意力层:通过自注意力机制计算特征间的相互影响,从而实现特征交互。
- 堆叠注意力层:可以通过堆叠多个注意力层来进一步增强模型的学习能力。
- 输出层:最后将注意力机制产生的特征交互结果传递给一个全连接层,以进行最终的预测。
c. 示例代码
import numpy as np
import pandas as pd
import torch
from torch.utils.data import TensorDataset, DataLoader
import torch.nn as nn
import torch.optim as optim
# 设置随机种子以确保结果的可重复性
np.random.seed(42)
torch.manual_seed(42)
# 随机生成一些数据
num_users = 100
num_items = 50
num_interactions = 1000
user_ids = np.random.randint(0, num_users, size=num_interactions)
item_ids = np.random.randint(0, num_items, size=num_interactions)
ratings = np.random.randint(1, 6, size=num_interactions) # 假设评分为1到5
data = pd.DataFrame({
'user_id': user_ids,
'item_id': item_ids,
'rating': ratings
})
# 显示数据样本
print(data.head())
# 转换为Tensor
users = torch.tensor(data['user_id'].values, dtype=torch.long)
items = torch.tensor(data['item_id'].values, dtype=torch.long)
ratings = torch.tensor(data['rating'].values, dtype=torch.float).view(-1, 1)
# 使用PyTorch DataLoader来处理数据
dataset = TensorDataset(users, items, ratings)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 自定义SelfAttention层
class SelfAttention(nn.Module):
def __init__(self, embed_dim, num_heads=1, dropout_rate=0.0):
super(SelfAttention, self).__init__()
self.embed_dim = embed_dim
self.num_heads = num_heads
self.dropout_rate = dropout_rate
self.q_dense = nn.Linear(embed_dim, embed_dim)
self.k_dense = nn.Linear(embed_dim, embed_dim)
self.v_dense = nn.Linear(embed_dim, embed_dim)
self.dropout = nn.Dropout(dropout_rate)
def forward(self, inputs):
q = self.q_dense(inputs)
k = self.k_dense(inputs)
v = self.v_dense(inputs)
attn_scores = torch.matmul(q, k.transpose(-1, -2)) / torch.sqrt(
torch.tensor(self.embed_dim, dtype=torch.float32))
attn_weights = torch.softmax(attn_scores, dim=-1)
attn_output = torch.matmul(self.dropout(attn_weights), v)
return attn_output
# 自定义模型
class AttentionModel(nn.Module):
def __init__(self, num_users, num_items, embedding_dim):
super(AttentionModel, self).__init__()
self.user_embedding = nn.Embedding(num_users, embedding_dim)
self.item_embedding = nn.Embedding(num_items, embedding_dim)
self.attention_layer = SelfAttention(embed_dim=embedding_dim, num_heads=1)
self.output_layer = nn.Linear(embedding_dim, 1)
def forward(self, user, item):
user_emb = self.user_embedding(user)
item_emb = self.item_embedding(item)
user_vec = user_emb.squeeze()
item_vec = item_emb.squeeze()
# 拼接用户和物品的嵌入向量
concat_embeddings = torch.stack([user_vec, item_vec], dim=1)
# 自注意力层
attention_output = self.attention_layer(concat_embeddings)
attention_output = torch.sum(attention_output, dim=1)
# 输出层
output = self.output_layer(attention_output)
return output
# 模型参数
embedding_dim = 8
# 构建模型
model = AttentionModel(num_users, num_items, embedding_dim)
# 损失函数和优化器
loss_fn = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
num_epochs = 10
for epoch in range(num_epochs):
for user, item, rating in dataloader:
prediction = model(user, item)
loss = loss_fn(prediction, rating)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
# 查看模型结构
print(model)
9. Recurrent Neural Networks (RNN) for Sequences
使用 RNN 来捕捉用户行为的时间序列特性,比如用户的点击流数据。
a. 模型特点
- 记忆效应:RNN 能够记住先前的信息,并将其与当前的信息相结合,从而更好地理解序列数据。
- 循环结构:RNN 具有一个循环的连接结构,允许信息在时间上被传递。
- 短期记忆:由于简单的 RNN 容易受到梯度消失或梯度爆炸问题的影响,它们通常只能记住短期的信息。
- 共享权重:在网络的不同时间步上,RNN 使用相同的权重矩阵,这有助于减少参数的数量并提高模型的泛化能力。
- 梯度消失/爆炸问题:由于长时间依赖的问题,RNN 在训练过程中可能会遇到梯度消失或梯度爆炸问题,这限制了它在长序列上的表现。
- 变种模型:为了克服这些问题,发展出了 LSTM (Long Short-Term Memory) 和 GRU (Gated Recurrent Unit) 等变种模型。
b. 设计思路
- 循环单元:在每个时间步 t,RNN 接收当前输入 xₜ 和前一时刻的状态 hₜ₋₁,计算当前状态 hₜ。
- 输出层:状态 hₜ 可以被进一步处理以生成输出 yₜ 或者直接用于下一个时间步的输入。
- 训练:通过反向传播算法(Backpropagation Through Time, BPTT)来更新权重。
- 总结:RNN 的基本思想是在处理序列数据时,将前一时刻的状态信息传递到下一时刻,以便当前时刻可以利用先前的信息。这通常是通过隐藏层的状态实现的,该状态在每个时间步都会更新。
c. 示例代码
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, Dataset
import numpy as np
# 构造模拟数据
np.random.seed(0) # 设置随机种子以确保结果可复现
actions = ['click_home', 'click_product', 'add_cart', 'checkout', 'purchase']
num_actions = len(actions)
data_length = 1000 # 总数据点数量
sequence_length = 5 # 序列长度
# 模拟点击流数据
def generate_data(num_samples, sequence_length):
data = []
labels = []
for _ in range(num_samples):
sequence = np.random.choice(num_actions, size=sequence_length)
data.append(sequence[:-1])
labels.append(sequence[1:])
return data, labels
data, labels = generate_data(data_length, sequence_length)
# 数据预处理
class ClickStreamDataset(Dataset):
def __init__(self, data, labels, num_actions):
self.data = np.array(data)
self.labels = np.array(labels)
self.num_actions = num_actions
def __len__(self):
return len(self.data)
def __getitem__(self, idx):
sample = self.data[idx]
label = self.labels[idx]
# 转换为 one-hot 编码
one_hot_sample = np.zeros((sample.shape[0], self.num_actions))
one_hot_sample[np.arange(sample.shape[0]), sample] = 1
return torch.tensor(one_hot_sample, dtype=torch.float), torch.tensor(label, dtype=torch.long)
dataset = ClickStreamDataset(data, labels, num_actions)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 定义 RNN 模型
class RNNModel(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super(RNNModel, self).__init__()
self.hidden_dim = hidden_dim
self.rnn = nn.RNN(input_dim, hidden_dim, batch_first=True)
self.fc = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
h0 = torch.zeros(1, x.size(0), self.hidden_dim).to(x.device)
out, _ = self.rnn(x, h0)
out = self.fc(out)
return out
model = RNNModel(input_dim=num_actions, hidden_dim=50, output_dim=num_actions)
# 损失函数和优化器
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 训练模型
epochs = 200
for epoch in range(epochs):
for batch, (X, y) in enumerate(dataloader):
# 前向传播
output = model(X)
# 调整 y 的形状以匹配 output 的最后一个维度
y = y.view(-1)
output = output.view(-1, num_actions)
# 计算损失
loss = loss_fn(output, y)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 预测下一个动作
def predict_next_action(model, sequence, num_actions):
model.eval()
with torch.no_grad():
one_hot_sequence = np.zeros((1, sequence.shape[0], num_actions))
one_hot_sequence[0, np.arange(sequence.shape[0]), sequence] = 1
X_onehot = torch.tensor(one_hot_sequence, dtype=torch.float)
output = model(X_onehot)
_, predicted = torch.max(output[:, -1, :], dim=1)
return actions[predicted.item()]
# 测试预测
test_sequence = torch.tensor([[0, 1, 2, 3]], dtype=torch.long)
next_action = predict_next_action(model, test_sequence.numpy(), num_actions)
print("Predicted next action:", next_action)
10. Convolutional Neural Networks (CNN) for Content
利用卷积神经网络来分析文本、图像等内容信息,进而推荐相似的内容给用户。
a. 模型特点
- 局部感知:CNN 中的神经元只与输入的一部分相连,这反映了特征的局部相关性。
- 权值共享:同一特征映射内的神经元共享权重,这样可以减少模型的参数数量,同时捕捉到平移不变性。
- 池化操作:通过池化层(如最大池化或平均池化)降低空间维度,从而减少计算量并控制过拟合。
b. 设计思路
CNN 的设计灵感来源于生物视觉系统的研究,特别是猫的初级视皮层中发现的细胞对特定区域的刺激响应。其基本组件包括卷积层、激活函数、池化层以及全连接层。卷积层负责提取特征,池化层负责下采样,全连接层则用来分类或其他高层任务。
c. 示例代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
import numpy as np
import matplotlib.pyplot as plt
# 设置随机种子以保证结果可复现
np.random.seed(42)
torch.manual_seed(42)
# 定义数据集大小和类别数
num_samples = 1000
num_classes = 2
# 生成两个不同均值的二维高斯分布样本
class_0 = np.random.multivariate_normal([5, 5], [[1, .75], [.75, 1]], num_samples // 2)
class_1 = np.random.multivariate_normal([10, 10], [[1, .75], [.75, 1]], num_samples - num_samples // 2)
# 将两类数据合并
features = np.vstack([class_0, class_1])
labels = np.hstack([np.zeros(num_samples // 2), np.ones(num_samples - num_samples // 2)])
# 打乱数据顺序
indices = np.arange(features.shape[0])
np.random.shuffle(indices)
features = features[indices]
labels = labels[indices]
# 将数据转换为图像形式,这里我们将其扩展到28x28大小
image_size = 28
features = np.reshape(features, (-1, 2))
images = np.zeros((num_samples, image_size, image_size))
for i, point in enumerate(features):
x, y = point * 28 / 15 # 将点映射到图像范围内
x, y = int(np.ceil(x)), int(np.ceil(y))
if 0 <= x < image_size and 0 <= y < image_size:
images[i, x, y] = 1 # 在图像上标记这个点
# 将图像数据归一化
images = images[..., np.newaxis] / 1. # 添加通道维度并归一化
# 划分训练集和测试集
split = int(0.8 * num_samples)
# 转换为 PyTorch 张量
train_images = torch.tensor(images[:split], dtype=torch.float).permute(0, 3, 1, 2)
test_images = torch.tensor(images[split:], dtype=torch.float).permute(0, 3, 1, 2)
train_labels = torch.tensor(labels[:split], dtype=torch.long)
test_labels = torch.tensor(labels[split:], dtype=torch.long)
# 构建数据加载器
batch_size = 32
train_dataset = TensorDataset(train_images, train_labels)
test_dataset = TensorDataset(test_images, test_labels)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
# 定义 CNN 模型
class ConvNet(nn.Module):
def __init__(self):
super(ConvNet, self).__init__()
self.conv_layers = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2)
)
self.fc_layers = nn.Sequential(
nn.Flatten(),
nn.Linear(64 * (image_size // 4) * (image_size // 4), 64),
nn.ReLU(),
nn.Linear(64, num_classes)
)
def forward(self, x):
x = self.conv_layers(x)
x = self.fc_layers(x)
return x
# 初始化模型
model = ConvNet()
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练模型
num_epochs = 5
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
for epoch in range(num_epochs):
model.train()
running_loss = 0.0
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
outputs = model(data)
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item() * data.size(0)
epoch_loss = running_loss / len(train_loader.dataset)
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {epoch_loss:.4f}')
# 评估模型
model.eval()
with torch.no_grad():
correct = 0
total = 0
for data, labels in test_loader:
data, labels = data.to(device), labels.to(device)
outputs = model(data)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Test Accuracy: {100 * correct / total:.2f}%')
# 可视化部分训练样本
plt.figure(figsize=(10, 10))
for i in range(25):
plt.subplot(5, 5, i + 1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i].squeeze().numpy(), cmap=plt.cm.binary)
plt.show()
11. Hybrid Models
结合多种模型的优点,如结合基于内容的过滤和协同过滤的方法。
a. 模型特点
- 互补性:基于内容的过滤可以利用物品的内容信息(如描述、标签等),而协同过滤可以利用用户的历史行为数据。结合两者可以弥补各自的不足。
- 鲁棒性:单一模型可能在某些情况下表现不佳,如冷启动问题(新用户或新物品缺乏历史数据),而混合模型可以更好地应对这些问题。
- 灵活性:可以根据具体应用场景和可用数据灵活调整模型的组成部分。
b. 设计思路
- 基于内容的过滤:通过分析物品的内容特征(如文本描述、标签等)来推荐相似的物品。这种方法适用于新用户或新物品。
- 协同过滤:基于用户的行为数据(如评分、点击等)来发现用户之间的相似性,并推荐相似用户喜欢的物品。这种方法适用于有足够历史数据的场景。
- 组合策略:将两种方法的结果进行组合,可以通过加权平均或其他方式来综合考虑两种推荐结果。
c. 示例代码
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
# 示例图数据
num_users = 100
num_items = 50
num_item_features = 10
# 用户-物品评分矩阵
ratings = np.random.randint(1, 6, size=(num_users, num_items))
# 物品内容特征矩阵
item_features = np.random.rand(num_items, num_item_features)
# 转换为PyTorch tensor
ratings_tensor = torch.from_numpy(ratings).float()
item_features_tensor = torch.from_numpy(item_features).float()
# 定义模型类
class HybridModel(nn.Module):
def __init__(self, num_users, num_items, num_item_features):
super(HybridModel, self).__init__()
# 嵌入层
self.user_embedding = nn.Embedding(num_users, 8)
self.item_embedding = nn.Embedding(num_items, 8)
# 物品特征编码层
self.item_fc = nn.Sequential(
nn.Linear(num_item_features, 16),
nn.ReLU(),
nn.Linear(16, 8),
nn.ReLU()
)
# 最终的全连接层
self.fc = nn.Linear(16, 1)
def forward(self, user_ids, item_ids, item_features):
user_emb = self.user_embedding(user_ids).squeeze()
item_emb = self.item_embedding(item_ids).squeeze()
item_feat_emb = self.item_fc(item_features)
dot_product = torch.mul(user_emb, item_emb).sum(dim=1, keepdim=True)
# 确保dot_product和item_feat_emb形状一致
dot_product = dot_product.expand(-1, 8)
combined = torch.cat([item_feat_emb, dot_product], dim=1)
return self.fc(combined)
# 实例化模型
model = HybridModel(num_users, num_items, num_item_features)
# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
# 准备训练数据
user_item_pairs = []
ratings_list = []
for user_id in range(num_users):
for item_id in range(num_items):
user_item_pairs.append([user_id, item_id])
ratings_list.append(ratings[user_id, item_id])
user_item_pairs = np.array(user_item_pairs)
ratings_list = np.array(ratings_list)
# 转换为PyTorch tensor
user_ids_tensor = torch.from_numpy(user_item_pairs[:, 0]).long()
item_ids_tensor = torch.from_numpy(user_item_pairs[:, 1]).long()
ratings_tensor = torch.from_numpy(ratings_list).float().unsqueeze(1)
item_features_tensor = item_features_tensor[user_item_pairs[:, 1]]
# 训练模型
for epoch in range(10):
optimizer.zero_grad()
predictions = model(user_ids_tensor, item_ids_tensor, item_features_tensor)
loss = criterion(predictions, ratings_tensor)
loss.backward()
optimizer.step()
print(f'Epoch {epoch + 1}, Loss: {loss.item()}')
# 测试模型
predictions = model(user_ids_tensor, item_ids_tensor, item_features_tensor)
print(predictions)