Torch教程(1)-Tensor

Torch是一个广泛支持机器学习算法的科学计算框架。易于使用且高效,主要得益于一个简单的和快速的脚本语言LuaJIT,和底层的C / CUDA实现。
核心特征的总结:
1. 一个强大的n维数组
2. 很多实现索引,切片,移调transposing的例程
3. 惊人的通过LuaJIT的C接口
4. 线性代数例程
5. 神经网络,并基于能量的模型
6. 数值优化例程
7. 快速高效的GPU支持
8. 可嵌入,可移植到iOS,Android和FPGA的后台
Torch目标是让你通过极其简单过程、最大的灵活性和速度建立自己的科学算法。Torch有一个在机器学习领域大型生态社区驱动库包,包括计算机视觉软件包,信号处理,并行处理,图像,视频,音频和网络等,基于Lua社区建立。Torch被Facebook人工智能研究实验室和位于伦敦的谷歌DeepMind大量使用。
我最近在学习torch,在学习的过程中,把学习的内容,总结为博客,在方便自己的同时,也能够分享给真正喜欢编程,喜欢计算机视觉的同行。

Tensor 介绍

Tensor是Torch中最基础的类,是网络基本的数据单元。在Torch7中,一个Tensor可以是任意维度的,维度数目可以通过LongStorage来设定,可以通过dim()或者nDimension()方法获取Tensor的维度,可以用size()获取所有的维度。例如:

x=torch.Tensor(1,2,3,2)
s=torch.LongStorage(5)
s[1] = 2                                                                      s[2] =2
s[3] = 2                                                                     s[4] = 4                                                                    s[5] = 1
print(x:nDimension()) # 5
x:size()
2
2
2
4
1
[torch.LongStorage of size 5]

在CNN网络中,Tensor一般来说是一个四维的数组,分别是batchSize, channel,width,height。在Torch中,数组的下标从1开始,到size()结束,这点和c/c++/java这些语言不同。访问Tensor的内容,可以直接使用下标的方式,或者使用Storage()函数。storage是Torch的一种访问内存的基本方式,有点类似C语言的数据类型。相关细节,参考文档here。
以一个三维的Tensor为例:

 th> x = torch.Tensor(5,5,5)
                                                                      [0.0001s] 
th> x[3][4][5]
2.1723719562371e-153    
                                                                      [0.0001s] 
th> x:storage()[x:storageOffset()+(3-1)*x:stride(1)+(4-1)*x:stride(2)+(5-1)*x:stride(3)]
2.1723719562371e-153    

storageOffset返回Tensor第一个位置(1),stride(i)返回第i维的长度。第二种方式,可以这样理解,storage()操作以后,在内存中本质是一维的数组结构,用相对于第一个位置的偏置,进行访问。*注意的是,在Tensor中同一行的元素总是连续的。*Tensor构造函数是不进行初始化值的,需要手动初始化。

th> x=torch.Tensor(4,5)                                                                   [0.0001s] 
th> i = 0                                                                     [0.0000s] 
th> x:apply(function()
..> i=i+1
..> return i
..> end)
  1   2   3   4   5
  6   7   8   9  10
 11  12  13  14  15
 16  17  18  19  20
[torch.DoubleTensor of size 4x5]                                                                     [0.0230s]  
th> x
  1   2   3   4   5
  6   7   8   9  10
 11  12  13  14  15
 16  17  18  19  20
[torch.DoubleTensor of size 4x5]                                                                    [0.0002s]   
th> x:stride()
 5
 1
[torch.LongStorage of size 2]

Torch中,Tensor主要有ByteTensor(无符号char),CharTensor(有符号),ShortTensor(shorts), IntTensor(ints), LongTensor(longs), FloatTensor(floats), DoubleTensor(doubles),默认存放为double类型,如果需要特别指出,通过torch.setdefaulttensortype()方法进行设定。例如torch.setdefaulttensortype(‘torch.FloatTensor’)。
在Torch中,所有的Tensor都共享同一个变量的内存,也就是说所有的操作都是在同一块内存上操作,这样的好处就是减少了内存复制所需要的时间,提高了运行速度,缺点也很明显,就是同一块内存的数据不能够持久,如果需要内存复制,可以使用copy()或者clone()方法。从下面的例子,可以看出这点:

th> x=torch.Tensor(2,2)
                                                                      [0.0001s] 
th> i = 0
                                                                      [0.0000s] 
th> x:apply(function()
..> i = i+1
..> return i
..> end)
 1  2
 3  4
[torch.DoubleTensor of size 2x2]

                                                                      [0.0002s] 
th> y = torch.Tensor(x)
                                                                      [0.0001s] 
th> y
 1  2
 3  4
[torch.DoubleTensor of size 2x2]

                                                                      [0.0002s] 
th> y:zero()
 0  0
 0  0
[torch.DoubleTensor of size 2x2]

                                                                      [0.0202s] 
th> x
 0  0
 0  0
[torch.DoubleTensor of size 2x2]

Tensor 基本函数

构造函数

Tensor构造函数,创建新的tensor,分配内存,但是不进行初始化值,tensor的值是随机产生的。Tensor主要有以下几种构造函数:

  • torch.Tensor() 空构造函数
  • torch.Tensor(tensor) 拷贝构造函数,但是这里共享了同一块内存。
  • torch.Tensor(sz1[,sz2[, sz3[, sz4]]]]) 创建4维的Tensor
  • torch.Tensor(sizes,[strides]) 使用longStorage方法创建任意维度的Tensor 。x=torch.Tensor(torch.LongStorage({4,4,3,2}))
  • torch.Tensor(table) torch.Tensor({{1,2,3,4}, {5,6,7,8}})。
  • torch.Tensor(storage, [storageOffset, sizes, [strides]])
th> s=torch.Storage(10):fill(1)
                                                                      [0.0001s] 
th> x=torch.Tensor(s,1,torch.LongStorage{2,5})
                                                                      [0.0001s] 
th> x
 1  1  1  1  1
 1  1  1  1  1
[torch.DoubleTensor of size 2x5]

                                                                      [0.0002s] 
  • torch.Tensor(storage, [storageOffset, sz1 [, st1 … [, sz4 [, st4]]]])

基本操作

复制

  • [Tensor] clone() 复制一个tensor,内存同样被复制
  • [Tensor] contiguous 内存连续则指向同样的内存返回,不连续,内存复制,返回Tensor。
  • [Tensor or string] type(type)返回Tensor的类型,直接使用type()返回Tensor类型,如果type有参数,可以进行Tensor的复制,如果原Tensor和新的tensor类型相同,两者指向同一片内存,不同的话则内存复制,新的tensor指向新内存。
  • [Tensor] typeAs(tensor) 与type 类似x:typeAs(y)
  • [boolean] isTensor(object) 判断是否为Tensor
  • [Tensor] byte(), char(), short(), int(), long(), float(), double() 想当于tensor的类型转换。

查询基本结构

  • [number] nDimension() &[number] dim() 返回Tensor的维度
  • [number] size(dim) 返回指定维度的大小
  • [LongStorage] size() 返回tensor的longstorage类型的结构,包括每一维的大小。
  • [number] stride(dim) 返回指定维度,从当前元素到下一个中间的数量。Torch的元素在同一行(最后一维)在内存中是连续的。
  • [LongStorage] stride() 返回tensor每一维从a[i]~a[i+1]中间元素数目
  • [Storage] storage() 将Tensor转化为一个一维的Storage
  • [boolean] isContiguous() 判断tensor在内存中是否连续。
  • [boolean] isSize(storage) 如果Tensor的维度和storage相同,返回真,否则返回假。
  • [boolean] isSameSizeAs(tensor) 判断两个tensor维度是否相同。
  • [number] nElement() 返回tensor的元素总数目。
  • [number] storageOffset() 返回tensor对应的storage的第一个位置(从1开始)。

查询操作

  • [] 使用下标访问符。如果下标index是数字,返回对应位置的值,如果是多维,则返回第一维的第i个切片。index是n个数字的表,这n个数则表示每一维对应的值,返回对应tensor的元素。index如果是LongStorage,这点和table相似。除此之外,index还可以是0/1的集合,表示一个掩码,这时返回tensor掩码位1的元素。
th> i = 0
                                                                      [0.0001s] 
th> x:apply(function() i = i +1 ;return i  end)
 1  2  3
 4  5  6
 7  8  9
[torch.DoubleTensor of size 3x3]

                                                                      [0.0003s] 
th> torch.le(x,3)
 1  1  1
 0  0  0
 0  0  0
[torch.ByteTensor of size 3x3]

                                                                      [0.0383s] 

Tensor指向现有的tensor或者内存

  • [self] set(tensor) 把原来的tensor复制给新的tensor,但是两者共享同一片内存,set方法不需要内存的复制,类似于c语音中的指针或者引用操作。
  • [boolean] isSetTo(tensor) 判断两者tensor是否经过set操作。只有两个tensors具有同样大小,同样的strides,并且共享同一块内存才返回正确。
  • [self] set(storage, [storageOffset, sizes, [strides]]) 将tensor指向storage空间,两者共享同一块内存,不存在内存复制。
th> s = torch.Storage(10):fill(1)
                                                                      [0.0001s] 
th> sz = torch.LongStorage({2,5})
                                                                      [0.0001s] 
th> x = torch.Tensor()
                                                                      [0.0000s] 
th> x:set(s, 1, sz)
 1  1  1  1  1
 1  1  1  1  1
[torch.DoubleTensor of size 2x5]

                                                                      [0.0002s] 
  • [self] set(storage, [storageOffset, sz1 [, st1 … [, sz4 [, st4]]]])

复制初始化

  • [self] copy(tensor) 用给定的tensor去替换self。两者元素的数目必须保持相同。
  • [self] fill(value) 用指定的value复制self。
  • [self] zero() 把self tensor全部置0。

Resize

  • [self] resizeAs(tensor) 根据原来的tensor调整大小,两者类型必须保持一致。
  • [self] resize(sizes) 根据LongStorage的大小调整tensor。
  • [self] resize(sz1 [,sz2 [,sz3 [,sz4]]]])

提取sub-tensor

这种类似于矩阵的切片操作,把tensor看作一个多维的立体,sub-tensor就是从不同的维度进行切分,获得那部分元素。主要方法有narrow,select,sub 和index,indexcopy两种类型,前面三种方法切片和原来的tensor共享同一块内存,修改sub-tensor同样会影响到原来的tensor,后面的两种使用了内存的复制,sub-tensor和原来的tensor之间不存在相互影响关系。

  • [self] narrow(dim, index, size) 返回一个tensor,数据内容在dim维度上,从index开始到index+size-1。
  • [Tensor] sub(dim1s, dim1e … [, dim4s [, dim4e]])
th> x = torch.Tensor(5,5):zero()
                                                                      [0.0001s] 
th> x:sub(2,3):fill(5)
 5  5  5  5  5
 5  5  5  5  5
[torch.DoubleTensor of size 2x5]

                                                                      [0.0002s] 
th> x
 0  0  0  0  0
 5  5  5  5  5
 5  5  5  5  5
 0  0  0  0  0
 0  0  0  0  0
[torch.DoubleTensor of size 5x5]

                                                                      [0.0002s] 
                                                                      th> x:sub(2,3,1,3):fill(4)
 4  4  4
 4  4  4
[torch.DoubleTensor of size 2x3]

                                                                      [0.0002s] 
th> x
 0  0  0  0  0
 4  4  4  5  5
 4  4  4  5  5
 0  0  0  0  0
 0  0  0  0  0
[torch.DoubleTensor of size 5x5]

                                                                      [0.0002s] 
  • [Tensor] select(dim, index) dim代表第几维,index代表第几个slice。
th> x:select(1,2):fill(2)
 2
 2
 2
 2
 2
[torch.DoubleTensor of size 5]

                                                                      [0.0002s] 
th> x
 0  0  0  0  0
 2  2  2  2  2
 4  4  4  5  5
 0  0  0  0  0
 0  0  0  0  0
[torch.DoubleTensor of size 5x5]

                                                                      [0.0003s] 
th> x:select(2,4):fill(5)
 5
 5
 5
 5
 5
[torch.DoubleTensor of size 5]

                                                                      [0.0001s] 
th> x
 0  0  0  5  0
 2  2  2  5  2
 4  4  4  5  5
 0  0  0  5  0
 0  0  0  5  0
[torch.DoubleTensor of size 5x5]

                                                                      [0.0002s] 
  • [Tensor] [{ dim1,dim2,… }] or [{ {dim1s,dim1e}, {dim2s,dim2e} }] 直接使用[]下标的形式进行复制操作。
  • [Tensor] index(dim, index) index与[]操作不同,index会复制内存,[]使用同一块内存。返回的tensor和原先的tensor之间不存在影响。dim表示第i维,index表示一个torch.LongTensor 的索引,表示第多少个dim,例如取x第1维的,第1,3,5行:
th> x = torch.rand(5,5)
                                                                      [0.0001s] 
th> y = x:index(1,torch.LongTensor{1,3,5})
                                                                      [0.0001s] 
th> y
 0.1808  0.0048  0.7778  0.9197  0.6483
 0.9615  0.7223  0.3947  0.2457  0.3692
 0.6159  0.4022  0.8646  0.9339  0.9750
[torch.DoubleTensor of size 3x5]

                                                                      [0.0003s] 
th> x
 0.1808  0.0048  0.7778  0.9197  0.6483
 0.0281  0.7912  0.2421  0.0364  0.7939
 0.9615  0.7223  0.3947  0.2457  0.3692
 0.7204  0.4008  0.7808  0.6333  0.1705
 0.6159  0.4022  0.8646  0.9339  0.9750
[torch.DoubleTensor of size 5x5]

                                                                      [0.0003s] 
  • [Tensor] indexCopy(dim, index, tensor) 复制原来tensor的值到当前tensor,通过index和dim设定复制到的位置。原来的tensor大小必须和设定的位置大小相同。
th> x = torch.rand(5,5)
                                                                      [0.0001s] 
th> x
 0.5205  0.4188  0.8317  0.5865  0.7641
 0.5979  0.6973  0.9968  0.7034  0.9907
 0.7545  0.1290  0.6260  0.0854  0.2256
 0.9613  0.7150  0.2935  0.4983  0.6745
 0.8547  0.0898  0.3636  0.2664  0.2693
[torch.DoubleTensor of size 5x5]

                                                                      [0.0003s] 
th> z = torch.rand(5,2)
                                                                      [0.0001s] 
th> z
 0.6829  0.8207
 0.6153  0.6383
 0.5977  0.0682
 0.9388  0.8328
 0.0213  0.4133
[torch.DoubleTensor of size 5x2]

                                                                      [0.0002s] 
th> x:indexCopy(2,torch.LongTensor{1,5},z)
 0.6829  0.8207
 0.6153  0.6383
 0.5977  0.0682
 0.9388  0.8328
 0.0213  0.4133
[torch.DoubleTensor of size 5x2]

                                                                      [0.0003s] 
th> x
 0.6829  0.4188  0.8317  0.5865  0.8207
 0.6153  0.6973  0.9968  0.7034  0.6383
 0.5977  0.1290  0.6260  0.0854  0.0682
 0.9388  0.7150  0.2935  0.4983  0.8328
 0.0213  0.0898  0.3636  0.2664  0.4133
[torch.DoubleTensor of size 5x5]

                                                                      [0.0004s] 
  • [Tensor] indexAdd(dim, index, tensor) 把原先tensor的内容加到当前tensor的指定位置上,位置由dim和index确定。
th> a = torch.Tensor(5,2):fill(100)
                                                                      [0.0001s] 
th> a
 100  100
 100  100
 100  100
 100  100
 100  100
[torch.DoubleTensor of size 5x2]

                                                                      [0.0003s] 
th> x:indexAdd(2,torch.LongTensor{1,2},a)
 100  100
 100  100
 100  100
 100  100
 100  100
[torch.DoubleTensor of size 5x2]

                                                                      [0.0004s] 
th> x
 100.6829  100.4188    0.8317    0.5865    0.8207
 100.6153  100.6973    0.9968    0.7034    0.6383
 100.5977  100.1290    0.6260    0.0854    0.0682
 100.9388  100.7150    0.2935    0.4983    0.8328
 100.0213  100.0898    0.3636    0.2664    0.4133
[torch.DoubleTensor of size 5x5]

                                                                      [0.0005s] 
  • [Tensor] indexFill(dim, index, val) 把value的值赋值到tensor指定的位置上,通过dim和index确定位置。
th> x:indexFill(2,torch.LongTensor{1,2},0)
0   
                                                                      [0.0002s] 
th> x
 0.0000  0.0000  0.8317  0.5865  0.8207
 0.0000  0.0000  0.9968  0.7034  0.6383
 0.0000  0.0000  0.6260  0.0854  0.0682
 0.0000  0.0000  0.2935  0.4983  0.8328
 0.0000  0.0000  0.3636  0.2664  0.4133
[torch.DoubleTensor of size 5x5]

                                                                      [0.0004s] 
  • [Tensor] gather(dim, index) gather返回一个新tensor,从原始的tensor的每“行”获取一组元素,该组元素的值有LongTensor结构指定位置。这个”行”可以这样理解,拿二维矩阵为例,dim = 1每一个row就是每行,dim = 2 就会得到每列数据,这样每列就看作一个行。这种全排列的意思。解释起来比较麻烦,希望大家多试试,就能发现规律。
th> x = torch.rand(5,5)
                                                                      [0.0001s] 
th> x
 0.0607  0.1297  0.5422  0.1601  0.9574
 0.8516  0.8973  0.7576  0.9423  0.7036
 0.2549  0.5626  0.0977  0.0586  0.3961
 0.3502  0.7438  0.3298  0.8991  0.2819
 0.7011  0.4185  0.4517  0.5621  0.6326
[torch.DoubleTensor of size 5x5]

                                                                      [0.0003s] 
th> y = x:gather(1, torch.LongTensor{{1, 2, 3, 4, 5}, {2, 4, 3, 5, 1}})
                                                                      [0.0001s] 
th> y
 0.0607  0.8973  0.0977  0.8991  0.6326
 0.8516  0.7438  0.0977  0.5621  0.9574
[torch.DoubleTensor of size 2x5]

                                                                      [0.0002s] 
th> z = x:gather(2, torch.LongTensor{{1, 3}, {2, 4}, {3, 5}, {4, 1}, {5, 2}})
                                                                      [0.0001s] 
th> z
 0.0607  0.5422
 0.8973  0.9423
 0.0977  0.3961
 0.8991  0.3502
 0.6326  0.4185
[torch.DoubleTensor of size 5x2]

                                                                      [0.0003s] 
  • [Tensor] scatter(dim, index, src|val) 把src或者val中的值写入到dim维和index指定的内存中。
th> x
 0.4603  0.5985  0.0979  0.5345  0.8319
 0.0198  0.2303  0.6146  0.7637  0.5176
[torch.DoubleTensor of size 2x5]

                                                                      [0.0002s] 

th> y = torch.zeros(3,5):scatter(1,torch.LongTensor{{1,2,3,1,1},{3,1,1,2,3}},x)
                                                                      [0.0001s] 
th> y
 0.4603  0.2303  0.6146  0.5345  0.8319
 0.0000  0.5985  0.0000  0.7637  0.0000
 0.0198  0.0000  0.0979  0.0000  0.5176
[torch.DoubleTensor of size 3x5]

                                                                      [0.0002s] 
  • [Tensor] maskedSelect(mask) 掩码版的select功能,需要指定binary的掩码,下同。
  • [Tensor] maskedCopy(mask, tensor)
  • [Tensor] maskedFill(mask, val)

查询操作

  • [LongTensor] nonzero(tensor) 返回tensor非0位置的坐标
th> x = torch.rand(3,3,3):mul(3):floor():int()
                                                                      [0.0001s] 
th> torch.nonzero(x)
 1  1  1
 1  1  2
 1  2  2
 1  2  3
 1  3  1
 1  3  2
 2  1  1
 2  1  2
 2  2  2
 2  3  1
 2  3  3
 3  1  1
 3  1  2
 3  1  3
 3  2  1
 3  3  2
[torch.LongTensor of size 16x3]

                                                                      [0.0004s] 

tensor的扩增/压缩

  • [result] expand([result,] sizes) expand函数不是分配新的内存,而是在原来的内存上增加新的内存,相当于两者共享一部分内存。
th> x = torch.rand(3,1)
                                                                      [0.0001s] 
th> x
 0.5418
 0.2531
 0.4533
[torch.DoubleTensor of size 3x1]

                                                                      [0.0002s] 
th> y = torch.expand(x,3,3)
                                                                      [0.0001s] 
th> y
 0.5418  0.5418  0.5418
 0.2531  0.2531  0.2531
 0.4533  0.4533  0.4533
[torch.DoubleTensor of size 3x3]

                                                                      [0.0002s] 
th> y:fill(5)
 5  5  5
 5  5  5
 5  5  5
[torch.DoubleTensor of size 3x3]

                                                                      [0.0002s] 
th> x
 5
 5
 5
[torch.DoubleTensor of size 3x1]

                                                                      [0.0001s] 
  • [Tensor] repeatTensor([result,] sizes) 将指定tensor重复指定次数。
th> x = torch.rand(3)
                                                                      [0.0001s] 
th> x
 0.9585
 0.3585
 0.9067
[torch.DoubleTensor of size 3]

                                                                      [0.0002s] 
th> torch.repeatTensor(x,3,3)
 0.9585  0.3585  0.9067  0.9585  0.3585  0.9067  0.9585  0.3585  0.9067
 0.9585  0.3585  0.9067  0.9585  0.3585  0.9067  0.9585  0.3585  0.9067
 0.9585  0.3585  0.9067  0.9585  0.3585  0.9067  0.9585  0.3585  0.9067
[torch.DoubleTensor of size 3x9]

                                                                      [0.0004s] 
  • [Tensor] squeeze([dim]) 移除所有的长度为1的维度。比如a[1][1][1]这种,直接压缩到a[1]既可以表达。

其他操作

  • [Tensor] transpose(dim1, dim2) 维度交换
  • [Tensor] t() 二维矩阵的转置操作
  • [self] apply(function) 类似于python map+lambda的功能。
  • [self] map(tensor, function(xs, xt))
  • [result] view([result,] tensor, sizes) 将存储空间变为任意维度的tensor展示。
  • [Tensor] permute(dim1, dim2, …, dimn) 将原来的tensor进行维度变换。
  • [Tensor] unfold(dim, size, step) 将原来的tensor进行折叠操作
  • [self] map2(tensor1, tensor2, function(x, xt1, xt2))
  • [result] split([result,] tensor, size, [dim]) 将一个tensor分为多个tensor。

你可能感兴趣的:(torch,lua,torch,深度学习)