翻译: 2.1深度学习pytorch数据处理

翻译: 2.1深度学习pytorch数据处理

为了完成任何事情,我们需要某种方式来存储和操作数据。一般来说,我们需要对数据做两件重要的事情:(i)获取它们;(ii) 一旦它们进入计算机就对其进行处理。如果没有某种方式来存储数据,获取数据是没有意义的,所以让我们先来玩弄合成数据。首先,我们介绍 𝑛 维数组,也称为张量。

如果您使用过 NumPy,这是 Python 中使用最广泛的科学计算包,那么您会发现本节很熟悉。无论您使用哪个框架,它的张量类(ndarray在 MXNet 中, Tensor在 PyTorch 和 TensorFlow 中)都与 NumPy 相似, ndarray但具有一些杀手级功能。首先,GPU 得到很好的支持以加速计算,而 NumPy 仅支持 CPU 计算。其次,张量类支持自动微分。这些属性使张量类适用于深度学习。在整本书中,当我们说张量时,我们指的是张量类的实例,除非另有说明。

2.1.1 入门

在本节中,我们的目标是让您开始并运行,为您配备基本的数学和数值计算工具,您将在阅读本书的过程中建立这些工具。如果您难以理解一些数学概念或库函数,请不要担心。以下部分将在实际示例的背景下重新审视这些材料,并且会深入了解。另一方面,如果您已经有一些背景并想更深入地了解数学内容,请跳过此部分。

首先,我们导入torch. 请注意,虽然它被称为 PyTorch,但我们应该导入torch而不是pytorch.

import torch

张量表示一个(可能是多维的)数值数组。对于一个轴,张量称为向量。有两个轴的张量称为矩阵。和 𝑘>2 轴,我们删除专门的名称,只是将对象称为 𝑘th 阶张量.

PyTorch 提供了多种函数来创建预先填充了值的新张量。例如,通过调用arange(n),我们可以创建一个等距值的向量,从 0(包括)开始,到n(不包括)结束。默认情况下,间隔大小为 1 . 除非另有说明,否则新张量存储在主内存中并指定用于基于 CPU 的计算。

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

我们可以通过检查张量的属性来访问张量的形状(沿每个轴的长度) 。shape

x.shape
torch.Size([12])

如果我们只想知道张量中元素的总数,即所有形状元素的乘积,我们可以检查它的大小。因为我们在这里处理的是一个向量,所以它的单个元素 shape与其大小相同。

x.numel()
12

要改变张量的形状而不改变元素的数量或它们的值,我们可以调用该reshape函数。例如,我们可以将张量 ,x从形状为 (12,) 的行向量转换为形状为 (3, 4) 的矩阵。这个新张量包含完全相同的值,但将它们视为组织为 3 行和 4 列的矩阵。重申一下,虽然形状发生了变化,但元素没有。请注意,大小不会因重塑而改变。

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

通过手动指定每个维度来重塑是不必要的。如果我们的目标形状是一个形状为(高度,宽度)的矩阵,那么在我们知道宽度之后,隐式给出高度。为什么我们必须自己执行除法?在上面的例子中,为了得到一个有 3 行的矩阵,我们同时指定它应该有 3 行和 4 列。幸运的是,张量可以自动计算出剩下的一维。-1我们通过放置我们希望张量自动推断的维度来调用此功能。在我们的例子中,我们可以等效地调用 or ,而不是调用。x.reshape(3, 4) x.reshape(-1, 4) x.reshape(3, -1)

通常,我们希望我们的矩阵使用零、一、其他一些常数或从特定分布中随机采样的数字进行初始化。我们可以创建一个张量来表示一个所有元素都设置为 0 且形状为 (2, 3, 4) 的张量,如下所示:

torch.zeros((2, 3, 4))
tensor([[[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]],

        [[0., 0., 0., 0.],
         [0., 0., 0., 0.],
         [0., 0., 0., 0.]]])

同样,我们可以创建每个元素设置为 1 的张量,如下所示:

torch.ones((2, 3, 4))
tensor([[[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]],

        [[1., 1., 1., 1.],
         [1., 1., 1., 1.],
         [1., 1., 1., 1.]]])

通常,我们希望从某个概率分布中随机抽取张量中每个元素的值。例如,当我们构造数组作为神经网络中的参数时,我们通常会随机初始化它们的值。下面的代码片段创建了一个形状为 (3, 4) 的张量。它的每个元素都是从标准高斯(正态)分布中随机采样的,均值为 0,标准差为 1。

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

2.1.2. 运算

这本书不是关于软件工程的。我们的兴趣不仅限于简单地从/向数组读取和写入数据。我们想对这些数组执行数学运算。一些最简单和最有用的操作是元素操作。这些将标准标量操作应用于数组的每个元素。对于将两个数组作为输入的函数,逐元素运算对两个数组中的每对对应元素应用一些标准二元运算符。我们可以从任何从标量映射到标量的函数创建一个元素函数。

在数学符号中,我们将通过签名 表示这样的一元标量运算符(接受一个输入) 𝑓:ℝ→ℝ . 这只是意味着该函数是从任何实数映射的( ℝ ) 到另一个上。同样,我们用签名表示二元标量运算符(取两个实际输入,并产生一个输出) 𝑓:ℝ,ℝ→ℝ . 给定任意两个向量 𝐮 和 𝐯 形状相同,二元算子 𝑓 ,我们可以产生一个向量 𝐜=𝐹(𝐮,𝐯) 通过设置 𝑐𝑖←𝑓(𝑢𝑖,𝑣𝑖) 对所有人 𝑖 , 在哪里 𝑐𝑖,𝑢𝑖 , 和 𝑣𝑖 是 𝑖th 向量的元素 𝐜,𝐮 , 和 𝐯 . 在这里,我们产生了向量值 𝐹:ℝ𝑑,ℝ𝑑→ℝ𝑑 通过 将标量函数提升为元素向量运算。

常见的标准算术运算符(+、-、*、/和**)都已升级为任意形状的任何形状相同的张量的元素运算。我们可以在任何两个相同形状的张量上调用元素操作。在下面的示例中,我们使用逗号来表示一个 5 元素元组,其中每个元素都是元素运算的结果。

2.1.2.1。运算

常见的标准算术运算符(+、-、*、/和**)已全部提升为元素运算。

x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y  # The ** operator is exponentiation
(tensor([ 3.,  4.,  6., 10.]),
 tensor([-1.,  0.,  2.,  6.]),
 tensor([ 2.,  4.,  8., 16.]),
 tensor([0.5000, 1.0000, 2.0000, 4.0000]),
 tensor([ 1.,  4., 16., 64.]))

可以按元素应用更多操作,包括像幂运算这样的一元运算符。

torch.exp(x)
tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])

除了元素计算之外,我们还可以执行线性代数运算,包括向量点积和矩阵乘法。我们将在2.3 节中解释线性代数的关键部分(没有假设的先验知识)。

我们还可以将多个张量连接在一起,将它们端到端堆叠以形成更大的张量。我们只需要提供张量列表并告诉系统沿着哪个轴连接。下面的示例显示了当我们沿行(轴 0,形状的第一个元素)与列(轴 1,形状的第二个元素)连接两个矩阵时会发生什么。我们可以看到第一个输出张量的axis-0长度( 6 ) 是两个输入张量的轴 0 长度之和 ( 3+3 ); 而第二个输出张量的轴 1 长度( 8 ) 是两个输入张量的轴 1 长度之和 ( 4+4 )。

X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
(tensor([[ 0.,  1.,  2.,  3.],
         [ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.],
         [ 2.,  1.,  4.,  3.],
         [ 1.,  2.,  3.,  4.],
         [ 4.,  3.,  2.,  1.]]),
 tensor([[ 0.,  1.,  2.,  3.,  2.,  1.,  4.,  3.],
         [ 4.,  5.,  6.,  7.,  1.,  2.,  3.,  4.],
         [ 8.,  9., 10., 11.,  4.,  3.,  2.,  1.]]))

有时,我们想通过逻辑语句构造一个二进制张量。举个例子。对于每个位置,如果 和在该位置相等,则新张量中的相应条目取值为 1,这意味着逻辑语句 在该位置为真;否则该位置为 0。

X == Y
tensor([[False,  True, False,  True],
        [False, False, False, False],
        [False, False, False, False]])

将张量中的所有元素相加得到一个只有一个元素的张量。

X.sum()
tensor(66.)

2.1.3 广播机制

在上一节中,我们看到了如何对两个相同形状的张量执行元素操作。在某些情况下,即使形状不同,我们仍然可以通过调用广播机制来执行元素操作。这种机制的工作方式如下:首先,通过适当地复制元素来扩展一个或两个数组,以便在此转换之后,两个张量具有相同的形状。其次,对结果数组执行元素操作。

在大多数情况下,我们沿着一个数组最初只有长度 1 的轴进行广播,例如在以下示例中:

a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a, b
(tensor([[0],
         [1],
         [2]]),
 tensor([[0, 1]]))

因为a和b是 3×1 和 1×2 矩阵,如果我们想添加它们,它们的形状不匹配。我们 将两个矩阵的条目广播到一个更大的 3×2 矩阵如下:对于矩阵a,它复制列,对于矩阵b,它在将两个元素相加之前复制行。

a + b
tensor([[0, 1],
        [1, 2],
        [2, 3]])

2.1.4 索引和切片

就像在任何其他 Python 数组中一样,张量中的元素可以通过索引访问。与任何 Python 数组一样,第一个元素的索引为 0,范围被指定为包括第一个但在最后一个元素之前。与标准 Python 列表一样,我们可以使用负索引根据它们与列表末尾的相对位置来访问元素。

因此,[-1]选择最后一个元素并[1:3]选择第二个和第三个元素,如下所示:

X[-1], X[1:3]
(tensor([ 8.,  9., 10., 11.]),
 tensor([[ 4.,  5.,  6.,  7.],
         [ 8.,  9., 10., 11.]]))

除了读取之外,我们还可以通过指定索引来写入矩阵的元素。

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

如果我们想为多个元素分配相同的值,我们只需索引所有元素,然后为它们分配值。例如, 访问第一行和第二行,其中获取沿轴 1(列)的所有元素。虽然我们讨论了矩阵的索引,但这显然也适用于向量和超过 2 维的张量。[0:2, :]:

X[0:2, :] = 12
X
tensor([[12., 12., 12., 12.],
        [12., 12., 12., 12.],
        [ 8.,  9., 10., 11.]])

2.1.5 节省内存

运行操作可能会导致将新内存分配给主机结果。例如,如果我们写,我们将取消引用曾经指向的张量,而是指向新分配的内存。在下面的示例中,我们使用 Python 的函数来演示这一点,它为我们提供了被引用对象在内存中的确切地址。运行后,我们会发现指向不同的位置。这是因为 Python 首先计算,为结果分配新内存,然后指向内存中的这个新位置。

before = id(Y)
Y = Y + X
id(Y) == before
False

出于两个原因,这可能是不可取的。首先,我们不想一直跑来跑去分配不必要的内存。在机器学习中,我们可能有数百兆字节的参数,并且每秒更新所有参数多次。通常,我们会希望就地执行这些更新。其次,我们可能会从多个变量中指向相同的参数。如果我们没有就地更新,其他引用仍将指向旧的内存位置,这使得我们的部分代码可能无意中引用过时的参数。
幸运的是,执行就地操作很容易。我们可以使用切片符号将操作的结果分配给先前分配的数组,例如. 为了说明这个概念,我们首先创建一个与另一个形状相同的新矩阵,用于分配一块Y[:] =

Z = torch.zeros_like(Y)
print('id(Z):', id(Z))
Z[:] = X + Y
print('id(Z):', id(Z))
id(Z): 139729336478400
id(Z): 139729336478400

如果 的值X在后续计算中没有被重用,我们也可以使用or来减少操作的内存开销。X[:] = X + Y

before = id(X)
X += Y
id(X) == before
True

转换为 NumPy 张量 ( ndarray),反之亦然,很容易。torch 张量和 numpy 数组将共享它们的底层内存位置,通过就地操作更改一个也会更改另一个。

A = X.numpy()
B = torch.from_numpy(A)
type(A), type(B)
(numpy.ndarray, torch.Tensor)

要将 size-1 张量转换为 Python 标量,我们可以调用 item函数或 Python 的内置函数。

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

2.1.7 总结

为深度学习存储和操作数据的主要接口是张量 ( 𝑛 维数组)。它提供了多种功能,包括基本数学运算、广播、索引、切片、内存节省以及转换为其他 Python 对象。

参考

https://d2l.ai/chapter_preliminaries/ndarray.html

Read more

用asp.net core结合fastdfs打造分布式文件存储系统

用asp.net core结合fastdfs打造分布式文件存储系统

最近被安排开发文件存储微服务,要求是能够通过配置来无缝切换我们公司内部研发的文件存储系统,FastDFS,MongDb GridFS,阿里云OSS,腾讯云OSS等。根据任务紧急度暂时先完成了通过配置来无缝切换内部文件系统以及FastDFS。至于MongDb GridFS,阿里云OSS,腾讯云OSS等则后期需要的话再开发对应的提供者程序集合。 作者:依乐祝 首发公众号:DotNetCore实战 原文链接: 今天主要是对开发过程,以及对FastDFS这个通用的分布式文件存储服务的单机及集群安装部署过程做个总结。希望对想要自建分布式文件系统的朋友有所帮助。 什么是FastDFS 这里先简单介绍下分布式文件存储系统。 FastDFS 是一个开源的高性能分布式文件系统(DFS)。 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡。主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务。 FastDFS 系统有三个角色:跟踪服务器(Tracker Server)、存储服务器(Storage Server)

By Ne0inhk
从零搭建分布式文件系统MinIO比FastDFS要更合适

从零搭建分布式文件系统MinIO比FastDFS要更合适

前两天跟大家分享了一篇关于如何利用FastDFS组件来自建分布式文件系统的文章,有兴趣的朋友可以阅读下《》。通过留言发现大家虽然感兴趣,但是都觉得部署比较麻烦。的确,fastdfs的部署很繁琐,而且也没有官方提供的针对.net core的sdk。而今天带来的MinIO则是一个比fastdfs更好的选择,可以让你足够简单的来部署使用,官方也提供了足够详细的api文档。下面就让我们开始今天的正文吧。 这里说明下为什么今天才进行分享,因为就在几个小时前官方才发布了最新的3.1.12版本的nuget包,解决了BucketExistsAsync的一个bug,不然你还得引用源码才能正常运行。 作者:依乐祝 原文地址: MinIO是什么? 官方对MinIO的介绍是:高性能,Kubernetes原生支持的对象存储系统。MinIO的高性能软件定义对象存储套件可以使用户能够为机器学习、分析和应用程序数据工作负载构建云原生支持的数据基础设施。下面是几个常用的网址 * 官网: * 开源地址: * 中文文档: * .NET 客户端api地址: * 下载地址: * minio-dotnet

By Ne0inhk
【半译】扩展shutdown超时设置以保证IHostedService正常关闭

【半译】扩展shutdown超时设置以保证IHostedService正常关闭

我最近发现一个问题,当应用程序关闭时,我们的应用程序没有正确执行在IHostedService中的StopAsync方法。经过反复验证发现,这是由于某些服务对关闭信号做出响应所需的时间太长导致的。在这篇文章中,我将展示出现这个问题的一个示例,并且会讨论它为什么会发生以及如何避免这种情况出现。 作者:依乐祝 首发地址: 英文地址: 使用IHostedService运行后台服务 ASP.NET Core 2.0引入。该: public interface IHostedService { Task StartAsync(CancellationToken cancellationToken); Task StopAsync(CancellationToken cancellationToken); } StartAsync在应用程序启动时被调用。在ASP.NET核心2.X发生这种情况在应用程序启动处理请求,而在ASP.NET核心3.x中托管服务开始在应用程序启动处理请求。 StopAsync当应用程序收到shutdown(SIGTERM)信号时(例如,您

By Ne0inhk
重学ASP.NET Core 中的标记帮助程序

重学ASP.NET Core 中的标记帮助程序

标记帮助程序是什么 标记帮助程序使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素。 例如,内置的 ImageTagHelper 可以将版本号追加到图片名称。  每当图片发生变化时,服务器都会为图像生成一个新的唯一版本号,因此客户端总能获得当前图像(而不是过时的缓存图像)。 作者:依乐祝 原文链接: 标记帮助程序的作用域是如何控制的 标记帮助程序作用域由 @addTagHelper、@removeTagHelper 和“!”选择退出字符等联合控制。下面就一一的进行相关的介绍吧。 使用 @addTagHelper 添加标记帮助程序 @addTagHelper 指令让视图可以使用标记帮助程序。 在这种情况下,视图文件是_pages/ViewImports,默认情况下,它由_pages_文件夹和子文件夹中的所有文件继承,这使得标记帮助程序可用。 这里公开标记帮助程序有两种方式,如下所示: 第一种:使用通配符语法(" * ")指定指定程序集(AspNetCore)中的所有标记帮助程序都可用于_Views_目录及其子目录中的每个视图文件。 @addTagHelp

By Ne0inhk