【theano-windows】学习笔记十一——theano中与神经网络相关函数

前言

经过softmaxMLP的学习, 我们发现thenao.tensor中除了之前的博客【theano-windows】学习笔记五——theano中张量部分函数提到的张量的定义和基本运算外, 还有一个方法称为nnet, 如果自己实现过前面两篇博客中的代码就会发现用到了theano.tensor.nnet.sigmoidthenao.tensor.nnet.tanh这两个神经网络的激活函数, 那么就应该想了, 这个nnet是否对于在theano中实现神经网络很重要呢?所以我就跑去看了一下官网的介绍了, 感觉有必要摘抄一波.

【注】本次学习只是摘抄点感觉常用的函数, 见到陌生的操作可以再去查官方文档

进入官方对nnet的介绍的界面时, 可以发现有五种操作

  • conv:卷积神经网络相关操作
  • nnet:神经网络相关操作
  • neighbours:卷积网络中图片的处理操作
  • bn: 批归一化batch normalization
  • blocksparse: 块稀疏乘法操作(有gemvouter)

国际惯例, 参考博客

Ops related to neural networks

Theano tutorial和卷积神经网络的Theano实现

卷积相关操作

2D卷积函数

theano.tensor.nnet.conv2d(input, filters, input_shape=None, filter_shape=None, border_mode='valid', subsample=(1, 1), filter_flip=True, image_shape=None, **kwargs)#默认翻转卷积核

参数解释:

  • input: 四维张量符号变量, 维度依次代表(批大小, 输入通道, 输入行, 输入列)
  • filters: 四维张量符号变量. 维度依次代表(输出通道, 输入通道, 滤波器行, 滤波器列)
  • input_shape: 可选变量, 可以是None, 也可以是四个整数或者常量组成的元组或者列表, 代表输入的大小
  • filter_shape: 可选变量, 可以是None, 也可以是四个整数或者常量组成的元组或者列表, 用于选择优化实现, 可以指定列表中某个元素为None, 表示这个元素在编译的时候是未知的
  • border_mode: 字符串, 整型, 或者两个整型组成的元组-以下任意一种
    valid: 输出大小inputshape−flitershape+1input shape-flitershape+1inputshapeflitershape+1
    full: 输出大小inputshape+filtershape−1inputshape+filtershape-1inputshape+filtershape1
    half: 使用rows//2rows//2rows//2行和colums//2colums//2colums//2列对称填充输入边界,然后执行valid
    int: 使用指定的全零宽度向量填充输入的对称边界, 然后使用valid
    (int1,int2): 使用int1行和int2列填充输入的对称边界, 然后执行valid
  • subsample: 长度为2的元组, 对输出进行下采样, 也称为步长strides
  • fliter_flip: 如果为True, 就在滑动卷积窗口前翻转filter, 翻转filter的操作经常称为卷积(convolution),而且这个值经常默认为True. 如果设置为False, 那么就不翻转filter, 这个操作一般叫做互相关(cross-correlation)
  • image_shape: 为None或者四个整型或者常变量组成的元组或者列表, input_shape的别名, 已弃用
  • filter_dilation:长度为2的元组, 对输入进行下采样, 经常称为空洞卷积(dilation),详细看知乎的解释如何理解空洞卷积(dilated convolution)?
  • kwargs: 兼容性, 常被忽略

返回值: 一系列的特征图, 大小是(批大小, 输出通道, 输出行, 输出列)

theano.sandbox.cuda.fftconv.conv2d_fft(input, filters, image_shape=None, filter_shape=None, border_mode='valid', pad_last_dim=False)

简介: 是仅支持GPUnnet.conv2d是实现, 使用了傅里叶变换来实现这个操作, 也会翻转卷积核. 但是conv2d_fft不能被直接使用, 因为没有提供梯度. 仅仅支持输入的最后一个维度是偶数, 其它的维度任意, 滤波器可以具有偶数或者技术的宽度. 如果你的输入一定具有奇数宽度, 那么可以使用填充的方法来解决, 如果你不确定你的输入倒是是偶数还是技术, 千万不要随便使用填充参数pad_last_dim, 因为这个参数是无条件的加接一个维度, 可能会让偶数输入变技术, 导致一些问题的发生…balabalabala后面一堆, 反正意思就是使用它挺麻烦的, 不如直接用nnet.conv2d

参数(在valid模式中输入必须大于滤波器)与上面的conv2d相同, 就是多了一个不一样的:

  • pad_last_dim: 无条件地对最后一个维度进行填充.返回结果时会删除这个填充的部分

3D卷积

theano.tensor.nnet.conv3d(input, filters, input_shape=None, filter_shape=None, border_mode='valid', subsample=(1, 1, 1), filter_flip=True, filter_dilation=(1, 1, 1))

参数:

  • input: 五维的符号张量. 每个维度分别代表(批大小, 输入通道, 输入深度, 输入行, 输入列)
  • filters: 五维的符号张量. 每个维度分别代表(输出通道, 输入通道, 滤波器深度, 滤波器行, 滤波器列)
  • input_shape: 输入参数大小
  • filter_shape: 滤波器参数大小
  • border_mode: 字符串, 整型, 或者两个整型组成的元组-以下任意一种
    valid: 输出大小inputshape−flitershape+1input shape-flitershape+1inputshapeflitershape+1
    full: 输出大小inputshape+filtershape−1inputshape+filtershape-1inputshape+filtershape1
    half: 使用filterrows//2filterrows//2filterrows//2行和filter//columsfilter//columsfilter//colums列对称填充输入边界,然后执行valid
    int: 使用指定的全零宽度向量填充输入的对称边界, 然后使用valid
    (int1,int2,int3): 使用int1int2和’int3’行填充输入的对称边界, 然后执行valid
  • subsample: 长度为3的元组, 对输出进行下采样, 也称为步长strides
  • fliter_flip: 如果为True, 就在滑动卷积窗口前翻转filter的’x,y,z’维度, 翻转filter的操作经常称为卷积(convolution),而且这个值经常默认为True. 如果设置为False, 那么就不翻转filter, 这个操作一般叫做互相关(cross-correlation)
  • filter_dilation:长度为3的元组, 对输入进行下采样, 经常称为空洞卷积(dilation)

返回值:卷积得到的特征图, 维度分别代表(批大小, 输出通道, 输出深度, 输出行, 输出列)

theano.sandbox.cuda.fftconv.conv3d_fft(input, filters, image_shape=None, filter_shape=None, border_mode='valid', pad_last_dim=False)

通过快速傅里叶变换fft执行卷积, 仅仅支持输入的最后一维是偶数. 其它的维度可以任意, 滤波器的最后一维可以是偶数或者奇数.

最后三个维度的语义并不重要, 只要他们在输入和滤波器之间的顺序是一样的就行.比如卷积如果是在图像里面执行的, 那么可以是(duration,height,width)也可以是(height,width,duration)…剩下的和conv2d_fft的描述一样, 就是如果你非要输入奇数维度, 请使用填充参数balabalabala…

theano.tensor.nnet.conv3d2d.conv3d(signals, filters, signals_shape=None, filters_shape=None, border_mode='valid')

简介: conv3d2d是使用conv2加上数据reshape实现的三维卷积操作, 某些情况下比conv3d快, 它在GPU上工作, 并且翻转卷积核. 包含视频的时空卷积

参数:

  • signals: 像素具有颜色通道的图像的时间序列, 形状是[Ns,Ts,C,Hs,Ws]
  • filters: 时空滤波器,维度[Nf, Tf, C, Hf, Wf]
  • signals_shape: 信号的维度
  • filter_shape: 滤波器的维度
  • border_mode: 这个与卷积相同, 有valid,full,half

注: 另一种定义signals的方法是(批, 时间, 输入通道, 行, 列) ; 另一种定义滤波器的方法(输出通道, 时间, 输入通道, 行, 列)

还有一堆其它的函数懒得贴了, 以后遇到了再说

神经网络相关操作

其实就是各种激活函数之类的:

##sigmoid

sigmoid(x)=11+e−xsigmoid(x)=\frac{1}{1+e^{-x}} sigmoid(x)=1+ex1

theano.tensor.nnet.nnet.sigmoid(x)
theano.tensor.nnet.nnet.ultra_fast_sigmoid(x)
theano.tensor.nnet.nnet.hard_sigmoid(x)
'''
hard_sigmoid: 1.0s
ultra_fast_sigmoid: 1.3s
sigmoid (with amdlibm): 2.3s
sigmoid (without amdlibm): 3.7s
'''

这里写图片描述

##softplus

softplus(x)=loge(1+ex)softplus(x)=log_e(1+e^x) softplus(x)=loge(1+ex)

theano.tensor.nnet.nnet.softplus(x)
#神经网络中的用法经常如下
x,y,b = T.dvectors('x','y','b')
W = T.dmatrix('W')
y = T.nnet.softplus(T.dot(W,x) + b)

##softsign

softsign=x1+abs(x)softsign=\frac{x}{1+abs(x)} softsign=1+abs(x)x

theano.tensor.nnet.nnet.softsign(x)

##softmax

softmaxij(x)=exij∑kexiksoftmax_{ij}(x)=\frac{e^{x_{ij}}}{\sum_k e^{x_{ik}}} softmaxij(x)=kexikexij

有一个小技巧就是这个softmax的计算是稳定的, 因为它采用了如下计算过程:

e_x = exp(x - x.max(axis=1, keepdims=True))
out = e_x / e_x.sum(axis=1, keepdims=True)

也就是说先减去了一个最大值, 随后才采用softmax的标准式子计算属于每个类别的概率(突然想到, 如果之前层用sigmoid激活, 是不是softmax就不需要减去最大值了么?因为sigmoid使得x∈{0,1}x\in\{0,1\}x{0,1},而使用Relu的话, 最好还是减一下, 但是总而言之, 无论是caffe还是theano都进行了减最大值操作). 为什么要减?因为如果上一层输出xxx很大, 那么编译器就会发生上溢出(e1000e^{1000}e1000)或者下溢出(e−1000e^{-1000}e1000), 那么减去最大值以后肯定不会上溢出了, 即使发生下溢出, 也会由于取对数而解决此问题. 详细原因请戳这里1,这里2

x,y,b = T.dvectors('x','y','b')
W = T.dmatrix('W')
y = T.nnet.softmax(T.dot(W,x) + b)

##Relu

theano.tensor.nnet.relu(x, alpha=0)

alpha是负值输入的斜率,属于0-1之间, 默认为0(标准的Relu), 如果是1的话, 激活函数就成线性激活了, 而其它的数就是传说中的Leaky Relu

因为这个函数比较重要, 所以扩展一下说明它的三种形式Relu,LeakyRelu,PRelu,摘自[Caffe]:关于ReLU、LeakyReLU 、PReLU layer

  • Relu
    forwardactivation:f(x)=max⁡(0,x)backwardgradient:∂E∂x={0,ifx≤0∂E∂y,ifx>0forward\ activation:f(x)=\max(0,x)\\ backward\ gradient:\frac{\partial E}{\partial x}=\begin{cases} 0 ,\ if\ x\leq0\\ \frac{\partial E}{\partial y}, if \ x>0 \end{cases} forward activation:f(x)=max(0,x)backward gradient:xE={0, if x0yE,if x>0

  • Leaky Relu
    forwardactivation:f(x)=max(0,x)+negativeslop∗min(0,x)backwardgradient:∂E∂x={v∗∂E∂y,ifx≤0∂E∂x,ifx>0forward\ activation: f(x)=max(0,x)+negativeslop*min(0,x)\\ backward\ gradient:\frac{\partial E}{\partial x}=\begin{cases} v*\frac{\partial E}{\partial y},\ if\ x\leq0\\ \frac{\partial E}{\partial x},\ if\ x>0 \end{cases} forward activation:f(x)=max(0,x)+negativeslopmin(0,x)backward gradient:xE={vyE, if x0xE, if x>0

  • Parametric Relu
    forwardactivation:f(xi)=max(0,xi)+ai∗min(0,xi)backwardactivation:{forxi:∂E∂xi={ai∂E∂yi,ifxi≤0∂E∂yi,ifxi>0forai:∂E∂ai={∑xixi∂E∂yi,ifxi≤00,ifxi>0forward\ activation: f(x_i)=max(0,x_i)+a_i*min(0,x_i)\\ backward \ activation: \begin{cases} for\ x_i:\frac{\partial E}{\partial x_i}=\begin{cases} a_i\frac{\partial E}{\partial y_i},\ if \ x_i\leq0\\ \frac{\partial E}{\partial y_i},\ if \ x_i>0 \end{cases}\\ for \ a_i: \frac{\partial E}{\partial a_i}=\begin{cases} \sum_{x_i}x_i\frac{\partial E}{\partial y_i},\ if \ x_i\leq0\\ 0,\ if\ x_i>0 \end{cases} \end{cases} forward activation:f(xi)=max(0,xi)+aimin(0,xi)backward activation:for xi:xiE={aiyiE, if xi0yiE, if xi>0for ai:aiE={xixiyiE, if xi00, if xi>0

binary_crossentropy

crossentropy(t,o)=−(t⋅log⁡(o)+(1−t)⋅log⁡(1−o))crossentropy(t,o)=-(t\cdot \log(o)+(1-t)\cdot \log(1-o)) crossentropy(t,o)=(tlog(o)+(1t)log(1o))

#theano.tensor.nnet.nnet.binary_crossentropy(output, target)
x, y, b, c = T.dvectors('x', 'y', 'b', 'c')
W = T.dmatrix('W')
V = T.dmatrix('V')
h = T.nnet.sigmoid(T.dot(W, x) + b)
x_recons = T.nnet.sigmoid(T.dot(V, h) + c)
recon_cost = T.nnet.binary_crossentropy(x_recons, x).mean()

categorical_crossentropy

返回近似分布和真实分布的交叉熵, 如果编码方案是基于给定的概率分布q而非真实分布p,那么两个概率分布之间的交叉熵衡量的就是从一系列的可能性中区分一个时间所需要的平均编码长度:
H(p,q)=−∑xp(x)log⁡(q(x))H(p,q)=-\sum_x p(x)\log(q(x)) H(p,q)=xp(x)log(q(x))

y = T.nnet.softmax(T.dot(W, x) + b)
cost = T.nnet.categorical_crossentropy(y, o)
# o is either the above-mentioned 1-of-N vector or 2D tensor

h_softmax

实现的是两层层级softmax, 如果输出的数目很重要的时候, 此函数就是softmax的另一个可选项

theano.tensor.nnet.h_softmax(x, batch_size, n_outputs, n_classes, n_outputs_per_class, W1, b1, W2, b2, target=None)

参数说明:

  • x:批大小*特征数, 也就是双层层级softmax的小批输入
  • batch_size: 输入x的小批大小
  • n_outputs: 输出的个数
  • n_classes:双层层级softmax的类别数, 对应第一个softmax的输出数目
  • n_outputs_per_class:每一类的输出个数
  • W1: 输入x的特征数*类别数, 第一个softmax的权重矩阵, 将输入x映射到类别概率
  • b1: 维度就是类别数, 第一个softmax的偏置
  • W2:(类别数*输入x的特征总数*n_outputs_per_class, 第二个softmax的权重矩阵
  • b2: 维度是n_classes*n_outputs_per_class,第二个softmax的偏置
  • target:维度是(batch_size,)或者(batch_size,1),对于每一个输入计算对应的目标输出, 如果为None, 那么就计算每个输入对应的所有输出

返回值: 取决于target, 它有两种不同大小的输出. 如果target没有指定(None)的时候, 那么所有的输出就被计算出来, 而且返回值大小为(batch_size,n_outputs), 反之, 当target指定以后, 仅仅有对应的输出被返回, 大小是(batch_size,1)

注意: n_output_per_classn_classes的乘积必须大于或者等于n_outputs,如果严格大于, 那么相关输出将会被忽略.n_outputs_per_classn_classes必须与W1,b1,W2b2的对应维度相同。计算效率最高的时候是当n_outputs_per_class和n_classes等于n_outputs的平方根时

【PS】感觉意思就是说返回的是(输入样本*预测出的标签)或者是(输入样本*所有可能标签的预测值), 到底是不是, 以后遇到再说.

卷积网络中处理图像的操作

images2neibs

#常用于池化操作
theano.tensor.nnet.neighbours.images2neibs(ten4, neib_shape, neib_step=None, mode='valid')

就不翻译文档了, 函数功能大概就是讲输入图像ten4按照大小为neib_shape的块滑动从图像中取块, 并将每一块拉成一个向量存着

参数:

  • ten4: 输入图像, 四维的, (dim1,dim2,row,col)前两个维度可以是通道和批
  • neib_shape: 包含两个值, 滑动窗口的高宽
  • neib_step:滑动的时候跳过的间隔, 类似于卷积的步长, 但是跳过的应该是块, 也就是说如果值为1, 那么每次取得的块是相邻但是不想交的, 比如(4,4)就是取行第1-4,5-8,9-12…的块, 而卷积是取1-4,2-5,3-6的块,这也就是为什么我们搜这个函数, 在谷歌上展示的都是实现池化操作的原因
  • mode:valid需要输入是池化因子的倍数,ignore_borders: 如果不是倍数, 就忽视边界

看个例子:

# Defining variables
images = T.tensor4('images',dtype= theano.config.floatX)
neibs = T.nnet.neighbours.images2neibs(images, neib_shape=(5, 5))# Constructing theano function
window_function = theano.function([images], neibs)# Input tensor (one image 10x10)
im_val = np.arange(100.,dtype=theano.config.floatX).reshape((1, 1, 10, 10))# Function application
neibs_val = window_function(im_val)print im_val
print neibs_val

可以发现原始图像为

[[[[  0.   1.   2.   3.   4.   5.   6.   7.   8.   9.][ 10.  11.  12.  13.  14.  15.  16.  17.  18.  19.][ 20.  21.  22.  23.  24.  25.  26.  27.  28.  29.][ 30.  31.  32.  33.  34.  35.  36.  37.  38.  39.][ 40.  41.  42.  43.  44.  45.  46.  47.  48.  49.][ 50.  51.  52.  53.  54.  55.  56.  57.  58.  59.][ 60.  61.  62.  63.  64.  65.  66.  67.  68.  69.][ 70.  71.  72.  73.  74.  75.  76.  77.  78.  79.][ 80.  81.  82.  83.  84.  85.  86.  87.  88.  89.][ 90.  91.  92.  93.  94.  95.  96.  97.  98.  99.]]]]

而用[5*5]的块滑动取值以后变成了

[[  0.   1.   2.   3.   4.  10.  11.  12.  13.  14.  20.  21.  22.  23.24.  30.  31.  32.  33.  34.  40.  41.  42.  43.  44.][  5.   6.   7.   8.   9.  15.  16.  17.  18.  19.  25.  26.  27.  28.29.  35.  36.  37.  38.  39.  45.  46.  47.  48.  49.][ 50.  51.  52.  53.  54.  60.  61.  62.  63.  64.  70.  71.  72.  73.74.  80.  81.  82.  83.  84.  90.  91.  92.  93.  94.][ 55.  56.  57.  58.  59.  65.  66.  67.  68.  69.  75.  76.  77.  78.79.  85.  86.  87.  88.  89.  95.  96.  97.  98.  99.]]

neibs2images

就是images2neibs的逆操作

theano.tensor.nnet.neighbours.neibs2images(neibs, neib_shape, original_shape, mode='valid')

可以把上面的neibs_val还原成原始图片矩阵

im_new = T.nnet.neighbours.neibs2images(neibs, (5, 5), im_val.shape)
# Theano function definition
inv_window = theano.function([neibs], im_new)
# Function application
im_new_val = inv_window(neibs_val)
print im_new_val

输出

[[[[  0.   1.   2.   3.   4.   5.   6.   7.   8.   9.][ 10.  11.  12.  13.  14.  15.  16.  17.  18.  19.][ 20.  21.  22.  23.  24.  25.  26.  27.  28.  29.][ 30.  31.  32.  33.  34.  35.  36.  37.  38.  39.][ 40.  41.  42.  43.  44.  45.  46.  47.  48.  49.][ 50.  51.  52.  53.  54.  55.  56.  57.  58.  59.][ 60.  61.  62.  63.  64.  65.  66.  67.  68.  69.][ 70.  71.  72.  73.  74.  75.  76.  77.  78.  79.][ 80.  81.  82.  83.  84.  85.  86.  87.  88.  89.][ 90.  91.  92.  93.  94.  95.  96.  97.  98.  99.]]]]

Batch Normalization

batch_normalization_train

theano.tensor.nnet.bn.batch_normalization_train(inputs, gamma, beta, axes='per-activation', epsilon=0.0001, running_average_factor=0.1, running_mean=None, running_var=None)

简介: 对于给定输入计算批归一化, 使用输入的均值和方差,下图摘自论文笔记-Batch Normalization

这里写图片描述
这里写图片描述
参数

  • axes: 输入的需要沿着哪个轴被归一化,取值为**‘per-activation’**, ‘spatial’ or a tuple of ints, 好像这个取值还会影响最终结果的好坏, 详细请戳这里
  • gamma: 缩放因子
  • beta: 偏置
  • epsilon:批归一化公式中的ϵ\epsilonϵ,最小1e−51e{-5}1e5
  • running_average_factor: 更新运行时均值和方差使用的更新因子
  • running_mean: running_mean * (1 - r_a_factor) + batch mean * r_a_factor
  • running_var:running_var * (1 - r_a_factor) + (m / (m - 1)) * batch var * r_a_factor

返回值:

  • out: 批归一化后的输入
  • mean: 沿着归一化轴的输入的均值
  • invstd: 沿着归一化轴的输入的逆标准差
  • new_running_mean: 运行时的均值
  • new_running_var: 运行时方差

这个函数的操作等价于:

# for per-activation normalization
axes = (0,)
# for spatial normalization
axes = (0,) + tuple(range(2, inputs.ndim))
mean = inputs.mean(axes, keepdims=True)
var = inputs.var(axes, keepdims=True)
invstd = T.inv(T.sqrt(var + epsilon))
out = (inputs - mean) * gamma * invstd + betam = T.cast(T.prod(inputs.shape) / T.prod(mean.shape), 'float32')
running_mean = running_mean * (1 - running_average_factor) + \mean * running_average_factor
running_var = running_var * (1 - running_average_factor) + \(m / (m - 1)) * var * running_average_factor

batch_normalization_test

theano.tensor.nnet.bn.batch_normalization_test(inputs, gamma, beta, mean, var, axes='per-activation', epsilon=0.0001)

对给定的输出使用给定的均值和方差进行批归一化, 参数就不说了, 输出是被归一化的输入. 这个操作的等价代码如下:

# for per-activation normalization
axes = (0,)
# for spatial normalization
axes = (0,) + tuple(range(2, inputs.ndim))
gamma, beta, mean, var = (T.addbroadcast(t, *axes)for t in (gamma, beta, mean, var))
out = (inputs - mean) * gamma / T.sqrt(var + epsilon) + beta

batch_normalization

theano.tensor.nnet.bn.batch_normalization(inputs, gamma, beta, mean, std, mode='low_mem')

与上面的区别就是这个函数虽然使用了GPU, 但是没有使用cuDNN优化,还有其它的暂时也不清楚, 以后遇到再看看具体用法

其它

##SparseBlockGemv

好像就是一个图像中取出某一块, 然后将它乘以一个矩阵之类并返回一条向量的操作, 调用方法不太懂, 是个类方法

class theano.tensor.nnet.blocksparse.SparseBlockGemv(inplace=False)

操作类似于这样

for b in range(batch_size):for j in range(o.shape[1]):for i in range(h.shape[1]):o[b, j, :] += numpy.dot(h[b, i], W[iIdx[b, i], oIdx[b, j]])

这个图解释的很清楚

这里写图片描述

也就是按照outputIdxinputIdxW进行索引, 然后与h对应位置相乘,而且也举了个例子当outputIdx=1也就是j=3时候的计算方法

make_node(o, W, h, inputIdx, outputIdx)

简介: 计算指定一条向量和矩阵的点乘.

参数:

  • o: 输出向量, 大小为(batch*, oWin, *oSize)
  • W: 权重矩阵, 大小为(iBlocks*, oBlocks, iSize, *oSize)
  • h: 低层的输入, 大小为(batch*, iWin, *iSize)
  • inputIdx: 输入块的索引, 大小为(batch*, *iWin)
  • outputIdx: 输出块的索引, 大小为 (batch*, *oWin)

返回值: dot(W[i, j], h[i]) + o[j], 大小为(batch, oWin, oSize)

注意:

  • batch:是批大小
  • iSize: 是每个输入块的大小
  • iWin: 是作为输入的块的数目, 这些块被inputIdx指定
  • oBlock: 是可能的输出块的数目
  • oSize: 是输出块的大小
  • oWin是输出块的数目, 可以被计算出来,每块是通过outputIdx计算的

SparseBlockOuter

class theano.tensor.nnet.blocksparse.SparseBlockOuter(inplace=False)

计算两组向量的外积, 使用结果更新整个矩阵, 操作类似于

for b in range(batch_size):o[xIdx[b, i], yIdx[b, j]] += (alpha * outer(x[b, i], y[b, j]))
make_node(o, x, y, xIdx, yIdx, alpha=None)

输入参数:

  • o: (xBlocks*, yBlocks, xSize, *ySize)
  • x: (batch*, xWin, *xSize)
  • y: (batch*, yWin, *ySize)
  • xIdx: x块的索引(batch*, *iWin)
  • yIdx: y块的索引(batch*, *oWin)

返回值:outer(x[i], y[j]) + o[i, j], 大小是(xBlocks, yBlocks, xSize, ySize)

注意

  • batch是批大小
  • xBlocks是x中的块的总数
  • xSize是这些x块中的每一个的大小。
  • xWin是将用作x的块的数量,将使用哪些块在xIdx中指定。
  • yBlocks是数字或可能的y块。
  • ySize是这些y块中的每一个的大小。
  • yWin是实际计算的y块的数量,将在yIdx中指定要计算的块。

sparse_block_dot

theano.tensor.nnet.blocksparse.sparse_block_dot(W, h, inputIdx, b, outputIdx)

简介: 计算指定的向量和矩阵的点积(加上偏差)

参数:

  • W: 权重矩阵, 大小为(iBlocks*, oBlocks, iSize, *oSize)
  • h: 低层输入, 大小为(batch*, iWin, *iSize)
  • inputIdx: 输入块的索引, 大小为 (batch*, *iWin)
  • b: 偏置向量, 大小为 (oBlocks*, *oSize)
  • outputIdx: 输出索引, 大小为 (batch*, *oWin)

返回值: dot(W[i, j], h[i]) + b[j], 大小是(batch, oWin, oSize)

注意

  • batch是批次大小。
  • iBlocks是输入(来自较低层)中的块的总数。
  • iSize是每个输入块的大小。
  • iWin是将用作输入的块的数量,哪些块将在inputIdx中指定,
  • oBlocks是数字或可能的输出块。
  • oSize是每个输出块的大小。
  • oWin1是实际计算的输出块数,将在outputIdx中指定要计算哪些块。

后记

这一次学习比较枯燥, 看了很多函数都不知道怎么用, 但是知道了里面有很多卷积操作, 提供了一堆激活函数和损失函数及其变种, 还可以实现池化操作, 具有batch normalize的实现, 还能指定对那一块进行乘法操作, 然后更新整个矩阵. 厉害了我的theano!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246634.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【caffe-windows】全卷积网络特征图分析

前言 突然就想分析一下全卷积网络的转置卷积部分了, 就是这么猝不及防的想法, 而且这个网络对图片的输入大小无要求,这么神奇的网络是时候分析一波了,我个人的学习方法调试代码,然后对照论文看理论 本次分析主要针对每层的权重大小和特征图…

【theano-windows】学习笔记十二——卷积神经网络

前言 按照进度, 学习theano中的卷积操作 国际惯例, 来一波参考网址 Convolutional Neural Networks (LeNet) 卷积神经网络如何应用在彩色图像上? 卷积小知识 三大特性:局部感知(稀疏连接), 权值共享, 池化 上图很重要, 描述的是前一个隐层m-1具有四…

【theano-windows】学习笔记十三——去噪自编码器

前言 上一章节学习了卷积的写法,主要注意的是其实现在theano.tensor.nnet和theano.sandbox.cuda.dnn中都有对应函数实现, 这一节就进入到无监督或者称为半监督的网络构建中. 首先是自编码器(Autoencoders)和降噪自编码器(denoising Autoencoders) 国际惯例, 参考网址: Denoi…

【theano-windows】学习笔记十四——堆叠去噪自编码器

前言 前面已经学习了softmax,多层感知器,CNN,AE,dAE,接下来可以仿照多层感知器的方法去堆叠自编码器 国际惯例,参考文献: Stacked Denoising Autoencoders (SdA) Greedy Layer-Wise Training of Deep Networks 理…

【theano-windows】学习笔记十五——受限玻尔兹曼机

前言 终于到了最喜欢的模型: 受限玻尔兹曼机(RBM)了, 发现关于RBM是如何从能量模型发展过来的介绍非常不错, 而关于详细理论证明, 可以去看我前面的受限玻尔兹曼机的一系列博客. 国际惯例, 参考博客,超级强推第二个博客, 证明过程很给力: Restricted Boltzmann Machines (R…

【Ogre-windows】环境配置

前言 由于工程原因, 学习一下Ogre面向对象图形渲染开源引擎, 慢慢爬坑吧。首先还是环境的配置问题哎. 其实最重要的是要预先编译三方库, 虽然官方说可以自动编译, 但是在自己电脑上还是出现了无法解析外部符号之类的问题, 正常情况下我就认为是三方库的lib出现了问题, 最后额外…

【theano-windows】学习笔记十六——深度信念网络DBN

前言 前面学习了受限玻尔兹曼机(RBM)的理论和搭建方法, 如果稍微了解过的人, 肯定知道利用RBM可以堆叠构成深度信念网络(deep belief network, DBN)和深度玻尔兹曼机(deep Boltzmann machine), 这里就先学习一下DBN. 国际惯例, 参考博文: Deep Belief Networks A fast lear…

【Ogre-windows】实例配置

前言 折腾了好久才搞定教程实例, 主要是因为上一篇博客安装的具体版本是Ogre1.10.9, 而官方的Ogre Wiki Tutorial Framework没有指定具体版本, 如果单纯下载Ogre Wiki Tutorial Framework 1.10 - (Windows line endings, updated 2015-10-15) 运行, 基本会血崩. 所以, 在经过仔…

【Ogre-windows】旋转矩阵及位置解析

前言 这篇博客主要针对三种问题 如何创建动画帧如何获取全局位置如何计算全局旋转矩阵 仿真环境为VS2013Ogre1.10.9与matlab验证 创建动画帧 这里只做一个简单的实验: 将自带的人物模型Jaiqua的run运动给新创建的运动myrun中并播放,直接贴代码了 void JaiQua:…

BP推导——续

前言 之前有证明过一次人工神经网络——【BP】反向传播算法证明 ,但是回头看的时候,有很多地方非常不严谨,特此拿出来再单独证明一次BP,并严格保证其严谨性。如果想看看粗略的证明,可以去看我之前的博客,毕…

matlab学习——强连通分量

前言 最近motion graph相关实验,发现实现运动过渡需要构建运动图,而为了避免运动过渡陷入死胡同,需要对图结构进行裁剪,方法就是计算图模型的极大强联通分量,但是自己懒得去实现,所以就去搜了一下matlab中…

【音频处理】离散傅里叶变换

前言 最近复现音乐驱动舞蹈的文章《Dancing-to-Music Character Animation》,用到了与傅里叶变换很相似的称为常Q变换的方法去分割音乐,所以对傅里叶变换做了一个小了解,本文不深入各种乱糟糟的理论,比如什么蝶形算法啥的&#x…

【音频处理】短时傅里叶变换

前言 上一篇博客讲了离散傅里叶变换,里面的实例是对整个信号进行计算,虽然理论上有N点傅里叶变换(本博客就不区分FFT和DFT了,因为它俩就是一个东东,只不过复杂度不同),但是我个人理解是这个N点是信号前面连续的N个数值…

【theano-windows】学习笔记十九——循环神经网络

前言 前面已经介绍了RBM和CNN了,就剩最后一个RNN了,抽了一天时间简单看了一下原理,但是没细推RNN的参数更新算法BPTT,全名是Backpropagation Through Time。 【注】严谨来说RNN有两个称呼:①结构上递归的recursive n…

【theano-windows】学习笔记二十——LSTM理论及实现

前言 上一篇学习了RNN,也知道了在沿着时间线对上下文权重求梯度的时候,可能会导致梯度消失或者梯度爆炸,然后我们就得学习一波比较常见的优化方法之LSTM 国际惯例,参考网址: LSTM Networks for Sentiment Analysis …

刚体运动学——欧拉角、四元数、旋转矩阵

前言 刚体运动旋转一般用:欧拉角、四元数、轴角对等表示,在对某个坐标旋转的时候,只需将欧拉角或四元数转换为旋转矩阵,并与原始坐标相乘,便可得到旋转以后的坐标。这里主要看看欧拉角、四元数和旋转矩阵。 国际惯例…

刚体运动学-四元数插值

前言 之前对写了一篇关于刚体运动学相关知识博客:刚体运动学——欧拉角、四元数、旋转矩阵,本篇博客就举例来说明,如何在运动捕捉数据中进行四元数插值。 国际惯例,参考博客: 探讨:向量(方向…

【TensorFlow-windows】学习笔记一——基础理解

前言 因为Theano已经停止更新了,所以在前面学完Theano搭建RBM,CNN,RNN相关结构以后,还是得选择一个主流框架的,由于我自身的学习最终是向强化学习靠近,可能用到的仿真环境是openai gym,所以选择了继续学习TensorFlow&…

【TensorFlow-windows】学习笔记二——低级API

前言 上一篇博客初步了解了tensorflow中建立机器学习模型的方法:可以使用eager execution和graph execution两种模式,可以使用高级API estimator中已经封装好的模型,也可以自己创建estimator,更重要的是我们也可以使用低级API自行…

【TensorFlow-windows】学习笔记五——自编码器

前言 上一篇博客介绍的是构建简单的CNN去识别手写数字,这一篇博客折腾一下自编码,理论很简单,就是实现对输入数据的重构,具体理论可以看我前面的【theano-windows】学习笔记十三——去噪自编码器 国际惯例,参考博客&…