ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

动手学深度学习:D2L环境搭建与张量数据处理全攻略

动手学深度学习:D2L环境搭建与张量数据处理全攻略 1. 从零搭好D2L环境依赖选择与安装避坑《动手学深度学习》Dive into Deep Learning简称D2L这本书我前前后后翻了三遍每次重读都有新收获。作为一本把理论和代码绑在一起的实战教材D2L的代码库封装得很干净但恰恰是这种“干净”让不少初学者卡在了第一步——环境装不上代码跑不起来。今天就围绕“安装、张量与数据处理”这三个最基础也最关键的模块把我实操中踩过的坑和沉淀下来的方法一次讲清楚。1.1 为什么选Miniconda而不是直接装Python很多刚入门的朋友习惯从Python官网下载安装包一路Next到底然后开始装PyTorch。这个思路在只做一两个小项目的场景下没问题但一旦你开始跟着D2L跑多章节代码、切换不同版本框架依赖冲突就会找上门。我个人的建议是宁可多花十分钟装Miniconda也别省这一步。Miniconda的核心价值不是Python本身而是环境隔离能力——每个项目有独立的Python解释器和包集合互不干扰。这就像你厨房里有多个灶台每个灶台只负责一道菜不会串味。具体安装步骤以Windows为例从Miniconda官网下载对应系统的安装包安装时勾选“Add Miniconda to my PATH environment variable”会让后续操作更省心但这个选项在新版安装器中默认隐藏需要展开高级选项才能看到。安装完成后打开Anaconda Prompt不是系统自带的cmd先验证conda是否可用conda --version创建D2L专属环境并激活conda create -n d2l python3.9 -y conda activate d2l为什么选Python 3.9而不是最新的3.11或3.12因为PyTorch和d2l包对最新Python版本的官方支持往往有滞后性3.9是经过大量验证的稳定区。等到你熟练了再根据自己的需求调整版本不迟。1.2 PyTorch与d2l包安装的完整流程环境激活后下一步是安装PyTorch。这里的关键决策是装CPU版还是GPU版。如果你有NVIDIA显卡且驱动和CUDA版本匹配那直接装GPU版能显著加快训练速度。判断方法是在命令行输入nvidia-smi如果能看到显卡信息就说明驱动正常。顶部显示的CUDA Version是驱动支持的最高CUDA版本比如显示CUDA 12.1那么选择PyTorch的CUDA 11.8或12.1的版本都能跑。我的建议是直接去PyTorch官网的Get Started页面选择对应配置后复制生成的命令。这是最稳妥的方式因为PyTorch的版本和CUDA版本有严格的对应关系手动装容易踩坑。以CUDA 12.1为例典型安装命令是pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121装完PyTorch后验证一下能否正常导入import torch print(torch.__version__) print(torch.cuda.is_available())torch.cuda.is_available()输出True说明GPU环境配置成功。接下来装d2l包。这个包是D2L作者封装的工具集包含了一些书里用到的数据加载、模型评估等辅助函数。安装命令很简单pip install d2l但如果你安装时报错别急着慌大概率是网络问题导致包下载中断。解决方案有两个使用国内镜像源加速pip install d2l -i https://pypi.tuna.tsinghua.edu.cn/simple如果下载中途失败常见提示如“子进程报错”或“Connection broken”先清理pip缓存再重试pip cache purge pip install d2l提示子进程报错大多是网络波动导致安装包下载不完整不是代码写错也不是Python版本问题。先加镜像源再清缓存重试这个组合拳基本能解决90%的安装问题。1.3 图形化开发环境的搭配选择环境装好后代码写在哪里D2L官方推荐Jupyter Notebook因为书里的代码本身就是Notebook格式逐段运行非常方便。我初期也是用Jupyter但后来发现跑复杂项目时Jupyter的调试能力确实弱一些。我现在的工作流是日常学习和跑D2L示例用Jupyter自己写独立项目或需要调试时用VS Code Python插件。VS Code对Python的支持已经非常成熟支持断点调试、变量监视而且能直接选择conda环境里的Python解释器不用额外配置。如果你想用PyCharm也行社区版免费且功能完整只需要在Settings里指定Project Interpreter为d2l环境下的Python路径即可。用哪个工具不重要核心是能高效地看到每一行代码的输出结果理解每一步在做什么。工具只是手段理解才是目的。2. 张量基础深度学习的“数字容器”到底怎么玩环境搞定后进入D2L的第二个大主题张量Tensor。很多人第一次看到“张量”这个词会觉得高深其实它就是多维数组的统称——标量是0维张量向量是1维张量矩阵是2维张量更高维的就是“除了行列还有更多轴”的数组。2.1 张量的创建与基本属性在PyTorch中创建张量最直接的方式和Python列表或NumPy数组很像import torch # 从列表创建 x torch.tensor([[1, 2, 3], [4, 5, 6]]) print(x) # 创建全0张量 zeros torch.zeros(2, 3) print(zeros) # 创建全1张量 ones torch.ones(2, 3) print(ones) # 创建随机张量均匀分布0-1 rand_tensor torch.rand(2, 3) print(rand_tensor) # 创建正态分布随机张量 randn_tensor torch.randn(2, 3) print(randn_tensor)张量有几个关键属性你需要立刻记住shape张量的形状比如torch.Size([2, 3])表示2行3列dtype数据类型比如torch.float32、torch.int64device张量所在的设备CPU还是GPU自己打印一下看输出就一目了然了。注意创建张量时如果没指定dtypePyTorch会根据输入数据自动推断。比如torch.tensor([1, 2, 3])默认是torch.int64而torch.tensor([1.0, 2.0, 3.0])默认是torch.float32。这在后面做数值计算时可能引发类型不匹配的问题最好在创建时显式指定x torch.tensor([1, 2, 3], dtypetorch.float32)2.2 张量运算加减乘除与广播机制张量最常用的操作就是各种数学运算。对应元素相加、相乘是最基础的x torch.tensor([1.0, 2.0, 3.0]) y torch.tensor([4.0, 5.0, 6.0]) print(x y) # 逐元素相加 print(x * y) # 逐元素相乘注意不是矩阵乘法 print(torch.dot(x, y)) # 点积返回标量很多初学者会混淆“逐元素相乘”和“矩阵乘法”。x * y是Hadamard积要求两个张量形状相同对应位置相乘而矩阵乘法用的是torch.matmul(x, y)或x y要求维度匹配比如2x3的矩阵只能乘3x4的矩阵。广播Broadcasting机制是张量运算里最有意思也最容易踩坑的地方。简单理解当两个形状不同的张量做运算时PyTorch会尝试把它们的形状“对齐”后自动扩展。举个例子a torch.tensor([[1, 2, 3], [4, 5, 6]]) # 2x3 b torch.tensor([10, 20, 30]) # 1x3 print(a b)这里b会被自动广播成[[10, 20, 30], [10, 20, 30]]然后和a逐元素相加。结果是tensor([[11, 22, 33], [14, 25, 36]])广播的规则可以概括为一句话从最后一个维度往前比对如果两个维度相等或其中一个为1就能广播否则报错。2.3 张量形状变换reshape、view与transpose数据处理的过程中你几乎不可能绕开形状变换。把一张28x28的图片展开成784维的向量这是全连接网络的输入要求把4张图片堆在一起变成4x28x28这是批量处理的基础。reshape和view是两种最常用的变形操作x torch.arange(12) # 生成0到11的序列 print(x.reshape(3, 4)) # 变成3行4列 # 用-1自动推断维度 print(x.reshape(-1, 4)) # 等价于reshape(3, 4) print(x.reshape(2, -1)) # 等价于reshape(2, 6)-1是PyTorch里的“自动计算”标记你只需要指定其他维度剩下的PyTorch帮你算。这个技巧在批量处理图片时特别有用比如你有一个形状为(batch_size, height, width)的张量想压平成(batch_size, height*width)直接写x.reshape(batch_size, -1)就行。view和reshape的区别在于view要求张量在内存中是连续存储的contiguous否则会报错reshape更聪明如果不能直接view它会自动拷贝一份再变形状。我的建议是优先用reshape性能差异可以忽略但省心不少。transpose用于交换维度比如把2x3变成3x2x torch.tensor([[1, 2, 3], [4, 5, 6]]) print(x.t()) # 转置对于高维张量交换特定维度用transpose(dim0, dim1)# 形状为(2, 3, 4)的张量交换第0维和第1维 y torch.rand(2, 3, 4) z y.transpose(0, 1) print(z.shape) # torch.Size([3, 2, 4])2.4 索引、切片与内存共享问题张量的索引和切片玩法跟NumPy基本一致但有一个细节特别容易被忽略切片返回的是视图view不是拷贝copy。也就是说修改切片会影响原张量。x torch.arange(12).reshape(3, 4) sub x[1:3, :] # 取第1行到第2行 sub[0, 0] 99 print(x) # 原张量的第1行第0列也变成了99这个特性在某些场景下是优点避免内存拷贝但在另一些场景下是坑不小心改了原数据。如果你需要独立修改子张量而不影响原数据显式调用clone()或copy()sub x[1:3, :].clone()2.5 张量与NumPy的转换深度学习的数据处理流程里NumPy和PyTorch张量经常交替使用。转换方式很简单import numpy as np # NumPy转张量 numpy_array np.array([[1, 2], [3, 4]]) tensor_from_np torch.from_numpy(numpy_array) # 张量转NumPy tensor torch.tensor([[1.0, 2.0], [3.0, 4.0]]) numpy_from_tensor tensor.numpy()这里要特别记住torch.from_numpy()转换出来的张量与原始NumPy数组共享内存。你改张量的值NumPy数组也会变。如果不想共享用torch.tensor(numpy_array)做一次拷贝。另外NumPy默认是float64而PyTorch张量默认是float32转换时注意类型是否匹配必要时用.float()或.double()统一。2.6 设备管理把张量放到GPU上在GPU环境下训练速度的提升主要来自张量运算的并行化。把张量移动到GPU只需一行代码# 先判断是否有GPU if torch.cuda.is_available(): device torch.device(cuda) else: device torch.device(cpu) x torch.tensor([1.0, 2.0, 3.0], devicedevice) # 或者先创建再移动 y torch.tensor([4.0, 5.0, 6.0]).to(device) print(x.device, y.device)这里有个常见的坑CPU张量和GPU张量不能直接做运算。比如你在CPU上创建了一个矩阵想和GPU上的张量相乘会报错“Expected all tensors to be on the same device”。解决办法就是统一用.to(device)把数据放到同一个设备上。我在刚开始写代码时经常犯这个错后来养成了一个习惯在每个模型的训练函数开头先把所有输入和模型参数都.to(device)后续就不再操心设备问题了。3. 数据处理从原始数据到模型输入的完整链路D2L书里对数据处理部分的处理方式刚开始看可能会觉得琐碎——为什么要写一堆载入函数直接读文件不就行了吗但当你真正开始做项目就会明白模型的性能上限很大程度上由数据质量决定而数据质量取决于预处理做得有多细。数据处理的标准化流程通常包含四步读取原始数据 → 清洗与预处理 → 转换为张量 → 批量加载。下面逐一展开。3.1 数据集的读取与构建从零写一个Dataset类PyTorch提供了torch.utils.data.Dataset基类但D2L书里为了方便教学会自己写一些辅助函数。理解Dataset类的结构比会调现成的接口更重要。一个最简单的自定义Dataset类需要实现三个方法from torch.utils.data import Dataset, DataLoader class MyDataset(Dataset): def __init__(self, data, labels): self.data data self.labels labels def __len__(self): return len(self.data) def __getitem__(self, idx): return self.data[idx], self.labels[idx]__len__返回数据集总大小__getitem__根据索引返回一个样本。这两个方法组成了PyTorch数据加载机制的核心——DataLoader在内部会不断调用__getitem__来获取样本然后打包成batch。在真实项目中__getitem__里还会塞入各种数据增强操作比如图像翻转、随机裁剪等。每取一次样本就对数据做一次变换这保证了训练时每次看到的数据都有细微差异提升了模型的泛化能力。3.2 DataLoader核心参数batch_size、shuffle与num_workersDataset定义好后用DataLoader加载dataset MyDataset(data, labels) dataloader DataLoader( dataset, batch_size32, shuffleTrue, num_workers0 )这三个参数是高频使用项我把它们拆开讲batch_size每个批次包含的样本数。这个值受显卡显存限制GPU显存小就调低一些比如16或8显存足可以调到64甚至128。D2L书里的很多示例用的是128或256但那是基于当时GPU的显存水平现在的显卡跑小模型可以适当调大。shuffle是否在每个epoch开始时打乱数据顺序。训练集必须设为True测试集通常设为False。原因很简单如果每个epoch用相同顺序喂数据模型会记住顺序而不是学习特征导致验证指标虚高。num_workers数据加载的子进程数。Windows上如果设为非0值可能会触发多进程相关的报错建议Windows用户先设为0跑通后再尝试调大。Linux和macOS设成min(8, CPU核心数)一般没问题。注意num_workers不是越大越好。每个worker会额外占用内存多进程之间的数据拷贝也有开销。我在实际项目中试过在普通笔记本上设4个worker已经不错设8个反而因为内存带宽瓶颈没有明显提升有时还会卡顿。遍历DataLoader的方式for batch_data, batch_labels in dataloader: # 这里batch_data的形状是(batch_size, ...) # batch_labels的形状是(batch_size,) print(batch_data.shape, batch_labels.shape) break这里有个概念必须反复强调整个训练过程就是“从DataLoader中不断取batch → 前向传播 → 计算损失 → 反向传播 → 更新参数”的循环。D2L书里的train_epoch函数把这个循环包装得很干净但你还是得亲手写一遍才能理解每个环节在干什么。3.3 数据预处理的标准动作尺寸调整、归一化与类型转换在把数据喂给模型之前还要经过几个标准处理步骤。以图像数据为例D2L里常用的Fashion-MNIST数据集本身就是28x28的灰度图处理起来相对简单。1. 尺寸调整Resize不同来源的图片尺寸往往不一致需要统一到模型期望的输入大小。PyTorch中可以用torchvision.transforms.Resizefrom torchvision import transforms transform transforms.Compose([ transforms.Resize((224, 224)), # 统一为224x224 transforms.ToTensor(), # PIL Image或numpy数组转Tensor值从0-255缩放到0-1 ])为什么很多视觉模型用224x224因为ImageNet数据集的标准尺寸就是224PyTorch的预训练模型默认输入也是这个尺寸。如果你用ResNet、VGG这些经典网络最好保持224x224否则输入维度不匹配。2. 像素归一化NormalizationToTensor()已经把像素值从0-255缩放到0-1但这还不够。为了让模型训练更稳定通常还会对每个通道做标准化使其均值为0、标准差为1transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])这组mean和std是ImageNet数据集的统计值在很多预训练模型的官方代码里都能看到。如果你用的是自己的数据集且没有预训练需求可以不套用这组值甚至不用Normalize但如果你要迁移学习、加载预训练权重就必须用和预训练时一致的标准化参数否则模型输入分布不匹配效果会大打折扣。3. 张量转换ToTensor在PyTorch中执行ToTensor()时注意它还会把图像的通道顺序从HWC改成CHW。这个细节非常重要——PIL读入的图片是(H, W, C)即高度、宽度、通道而PyTorch模型期望的输入是(C, H, W)即通道在前。ToTensor()会帮你做这个转置所以要确保在正确的位置调用它。如果你用NumPy处理数据想手动转换可以这样import numpy as np # 假设img是一个形状为(H, W, C)的numpy数组 img_tensor torch.from_numpy(img.transpose(2, 0, 1)).float() / 255.0手写和ToTensor()等价但更容易理解发生了什么。3.4 实际案例用Fashion-MNIST走通整个处理流程为了把上面的内容串起来我带你手写一个完整的Fashion-MNIST加载流程不依赖torchvision自带的数据集接口而是自己用原始文件构建Dataset这样你能看到处理链路的全貌。import torch from torch.utils.data import Dataset, DataLoader from torchvision import transforms import numpy as np class FashionMNISTCustom(Dataset): def __init__(self, images_path, labels_path, transformNone): # 这里以原始二进制文件为例 self.images self._load_images(images_path) self.labels self._load_labels(labels_path) self.transform transform def _load_images(self, path): with open(path, rb) as f: data np.frombuffer(f.read(), dtypenp.uint8, offset16) return data.reshape(-1, 28, 28) def _load_labels(self, path): with open(path, rb) as f: data np.frombuffer(f.read(), dtypenp.uint8, offset8) return data def __len__(self): return len(self.labels) def __getitem__(self, idx): image self.images[idx] label self.labels[idx] # 处理成CHW格式 image torch.from_numpy(image).float().unsqueeze(0) # (1, 28, 28) if self.transform: image self.transform(image) return image, torch.tensor(label, dtypetorch.long)然后构建训练集和DataLoadertrain_dataset FashionMNISTCustom( data/train-images-idx3-ubyte, data/train-labels-idx1-ubyte, transformtransforms.Compose([ transforms.Normalize((0.5,), (0.5,)) ]) ) train_loader DataLoader(train_dataset, batch_size64, shuffleTrue, num_workers0)这里Normalize用的均值0.5和标准差0.5表示原始像素值从0-1映射到-1到1之间。很多生成模型都会采用这种中心化处理。遍历一轮看看输出for images, labels in train_loader: print(Images shape:, images.shape) # torch.Size([64, 1, 28, 28]) print(Labels shape:, labels.shape) # torch.Size([64]) print(Label values:, labels[:10]) break你看到的torch.Size([64, 1, 28, 28])就是标准的模型输入格式64个样本、1个通道灰度、高28宽28。3.5 真实项目中的数据处理流程框架化思维D2L书里的数据处理相对简洁但真实项目的数据处理链路往往长得多。我把常见的数据处理框架整理成一个模块化的pipeline你可以根据自己的场景裁剪数据收集从数据库、日志文件、API接口等源头获取原始数据。这一步决定了后续所有工作的走向数据源质量问题很难靠预处理补救。数据清洗处理缺失值填充或删除、异常值用统计方法识别并处理、去重、格式统一。数据转换数值型特征标准化或归一化类别型特征做one-hot编码文本数据做分词和向量化图像数据做尺寸调整。数据增强训练集上做随机旋转、裁剪、翻转等操作增加样本多样性。这个环节通常是模型精度提升的关键。张量化与分批把处理好的数据封装成Tensor用DataLoader按batch喂给模型。在D2L的代码中第4步数据增强在图像分类章节才引入但现实项目中几乎从一开始就要考虑。3.6 张量与数据处理框架的选型思路目前PyTorch生态里张量处理和数据处理已经形成了相对标准的工具链Tensor是核心数据结构所有矩阵运算、自动求导都围绕它展开torchvision.transforms用于图像数据的预处理torch.utils.data.Dataset和DataLoader用于数据封装和批量加载torch.utils.data.random_split用于数据集划分训练/验证/测试这几年也出现了不少专门做数据处理的库比如torchdata、WebDataset等它们解决的是大规模数据流式加载的问题适合数据量超过内存容量的场景。初学者先不用碰这些把基础的Dataset和DataLoader玩熟已经能解决大多数问题。要不要一上来就学大型数据处理框架我的建议是不要。框架是为复杂场景服务的在基础里多花时间把Dataset、DataLoader、transform的理解打牢后面用任何框架都是手到擒来的事。4. 常见报错与排查速查表跑D2L代码时遇到的报错绝大多数集中在以下几类。我把排查思路整理成表方便你快速对照。4.1 安装阶段的报错现象可能原因解决方案pip安装d2l时提示“Connection broken”网络不稳定导致下载中断使用国内镜像源清pip缓存后重试pip安装时子进程报错退出码非0下载的wheel包不完整或与系统不兼容指定镜像源、升级pippip install --upgrade pip、确认Python版本在3.8-3.10之间conda创建环境很慢conda默认源访问慢更换conda国内镜像源或直接用pip install配合venvPyTorch安装后import torch报错下载了不匹配的版本去PyTorch官网重新复制安装命令不要用pip install torch这种不带索引地址的命令提示最稳妥的安装组合是——Miniconda创建Python 3.9环境 → 官网复制PyTorch安装命令 → pip安装d2l。这三步只要顺序对、网络好基本不会出问题。4.2 张量操作阶段的报错现象可能原因解决方案RuntimeError: The size of tensor a (4) must match the size of tensor b (3)两个张量形状不匹配检查shape确认是否需要reshape或广播RuntimeError: result type Float cant be cast to the desired output type Longdtype不一致用.float()、.long()统一类型RuntimeError: Expected all tensors to be on the same deviceCPU和GPU张量混用统一用.to(device)搬到同一设备view报错“is not contiguous”张量在内存中不连续用reshape替代view或先调用.contiguous()多维索引结果比预期少一维索引时用了单个数字而不是切片想要保持维度用x[1:2, :]而不是x[1, :]这里第5个问题特别常见容易出错觉x[1, :]取出的结果是1维张量而x[1:2, :]取出的是2维张量形状为1x3。如果你要拼接或矩阵运算维度数对不上就会报错。4.3 数据处理阶段的报错现象可能原因解决方案DataLoader迭代时卡住或报多进程错误Windows下num_workers设置不当设num_workers0放在if __name__ __main__:下执行IndexError: index out of range__getitem__里索引越界检查__len__返回值是否正确考虑__len__返回0的情况图片读入后维度不对忘了转成CHW格式用x.permute(2, 0, 1)或直接交给ToTensor()训练时每次epoch准确率波动巨大没开shuffleTrue训练集DataLoader的shuffle设为True4.4 排查思路先看栈顶再查数据我自己排查报错的习惯是先看最后几行错误信息了解是什么类型的错误再从错误信息往上找具体是哪个函数、哪一行代码触发的然后判断是数据问题、类型问题还是逻辑问题。还有一个屡试不爽的排查手段小规模试跑。先把数据量截取前100条手动检查每一步的输出形状和内容# 调试小技巧单独取一个样本看形状 sample_img, sample_label train_dataset[0] print(sample_img.shape, sample_item_label) print(sample_img.min(), sample_img.max())确保数据从Dataset里出来就是对的再排查DataLoader的问题——这个思路能帮你把问题范围缩小一大半。5. 我的学习路径建议与实际操作心得D2L前几章的内容我见过太多人“看过就忘”。原因在于书里的代码太流畅了跟着敲一遍觉得自己会了但一离开Notebook就写不出来。根据我的经验有效学习方式是这样的。5.1 不要只敲一遍代码第一遍看书的时候只跟着敲一遍代码、看输出这远远不够。我推荐“三遍法”第一遍照着书里代码敲一遍理解每一行的作用。第二遍关掉答案凭理解自己写出章节的核心功能。比如看完张量章节后试着不看源码实现一个自制的线性回归模型。第三遍对代码做“破坏性改动”——比如改掉某个参数、换一种数据预处理方式观察结果变化猜原因。第三遍的做法对我帮助最大。比如在数据处理章节我把Normalize去掉后跑了一遍训练发现模型收敛变慢这就让我真正理解了归一化对训练的加速作用——比单看书上那句“标准化可以让训练更稳定”要深刻得多。5.2 从“抄代码”到“写代码”的过渡D2L从第五章开始引入多层感知机从第九章开始进入CNN。这时候代码的复杂度上了一个台阶。我的建议是不要只盯着模型的定义而是把所有代码看作“数据处理流水线 模型定义 训练循环”三个模块。数据处理流水线负责把原始数据变成模型输入的Tensor模型定义用nn.Module定义网络结构训练循环迭代数据处理流程计算损失更新参数这种模块化的思维方式一旦建立你会发现D2L书里不管是LeNet还是ResNet代码结构都是一样的骨架只是内部结构不同。这个认知会帮你大幅提升代码阅读速度和手写能力。5.3 张量和数据处理的扩展方向把D2L前两章彻底吃透后可以根据自己的方向做扩展如果做计算机视觉下一步学习torchvision.transforms的全部API特别是数据增强相关的变换随机裁剪、颜色抖动、AutoAugment如果做自然语言处理重点学习文本数据的构建方式tokenization、embedding以及如何处理变长序列padding、mask如果做时间序列或推荐系统学习如何处理表格类数据和稀疏特征无论哪个方向核心能力都是共通的把复杂的数据变成张量把张量组织成有效的批量数据用批量数据驱动模型训练。这些能力在D2L的前两章里已经被训练得很扎实了。5.4 最后一个小建议我在跑了无数遍数据加载循环之后养成了一个习惯每次写一个新的数据处理流程都先打印一个batch的数据形状确认输入格式无误后再开始训练。这个习惯替我避免了很多无意义的debug时间。如果你在环境配置时遇到子进程报错或者在张量操作时遇到维度问题都不必沮丧——每个跑通D2L的人都经历过这些。按照上文的方法一步步排查你很快就能把基础打得比大多数“速成党”扎实得多。数据集已经就位每个batch按预期形状输出训练循环一启动你手边的显卡风扇开始转起来的那一刻你会觉得之前的折腾全是值得的。
返回列表