encoding.py 3.14 KB
Newer Older
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
1
2
##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
## Created by: Hang Zhang
Zhang's avatar
v0.4.2  
Zhang committed
3
4
## Email: zhanghang0704@gmail.com
## Copyright (c) 2018
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
5
6
##
## This source code is licensed under the MIT-style license found in the
Hang Zhang's avatar
sync BN  
Hang Zhang committed
7
## LICENSE file in the root directory of this source tree
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
8
9
##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Hang Zhang's avatar
sync BN  
Hang Zhang committed
10
"""Functions for Encoding Layer"""
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
11
12
import torch
from torch.autograd import Function, Variable
Zhang's avatar
v0.4.2  
Zhang committed
13
from .. import lib
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
14

Hang Zhang's avatar
v0.1.0  
Hang Zhang committed
15
__all__ = ['aggregate', 'scaledL2']
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
16
17

class _aggregate(Function):
Hang Zhang's avatar
v0.1.0  
Hang Zhang committed
18
    @staticmethod
Hang Zhang's avatar
sync BN  
Hang Zhang committed
19
    def forward(ctx, A, X, C):
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
20
        # A \in(BxNxK) R \in(BxNxKxD) => E \in(BxNxD)
Hang Zhang's avatar
sync BN  
Hang Zhang committed
21
        ctx.save_for_backward(A, X, C)
Zhang's avatar
v0.4.2  
Zhang committed
22
23
        if A.is_cuda:
            E = lib.gpu.aggregate_forward(A, X, C)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
24
        else:
Zhang's avatar
v0.4.2  
Zhang committed
25
            raise NotImplemented
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
26
27
        return E

Hang Zhang's avatar
v0.1.0  
Hang Zhang committed
28
    @staticmethod
Hang Zhang's avatar
sync BN  
Hang Zhang committed
29
30
    def backward(ctx, gradE):
        A, X, C = ctx.saved_variables
Zhang's avatar
v0.4.2  
Zhang committed
31
32
        if A.is_cuda:
            gradA, gradX, gradC = lib.gpu.aggregate_backward(gradE, A, X, C)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
33
        else:
Zhang's avatar
v0.4.2  
Zhang committed
34
            raise NotImplemented
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
35
36
37
        return gradA, gradX, gradC

def aggregate(A, X, C):
Zhang's avatar
v0.4.2  
Zhang committed
38
    r""" Aggregate operation, aggregate the residuals of inputs (:math:`X`) with repect
Hang Zhang's avatar
sync BN  
Hang Zhang committed
39
    to the codewords (:math:`C`) with assignment weights (:math:`A`).
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
40
41

    .. math::
Zhang's avatar
v0.4.2  
Zhang committed
42

Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
43
44
45
        e_{k} = \sum_{i=1}^{N} a_{ik} (x_i - d_k)

    Shape:
Hang Zhang's avatar
sync BN  
Hang Zhang committed
46
47
48
49
        - Input: :math:`A\in\mathcal{R}^{B\times N\times K}`
          :math:`X\in\mathcal{R}^{B\times N\times D}` :math:`C\in\mathcal{R}^{K\times D}`
          (where :math:`B` is batch, :math:`N` is total number of features,
          :math:`K` is number is codewords, :math:`D` is feature dimensions.)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
50
51
52
53
54
55
56
57
58
59
        - Output: :math:`E\in\mathcal{R}^{B\times K\times D}`

    Examples:
        >>> B,N,K,D = 2,3,4,5
        >>> A = Variable(torch.cuda.DoubleTensor(B,N,K).uniform_(-0.5,0.5), requires_grad=True)
        >>> X = Variable(torch.cuda.DoubleTensor(B,N,D).uniform_(-0.5,0.5), requires_grad=True)
        >>> C = Variable(torch.cuda.DoubleTensor(K,D).uniform_(-0.5,0.5), requires_grad=True)
        >>> func = encoding.aggregate()
        >>> E = func(A, X, C)
    """
Hang Zhang's avatar
v0.1.0  
Hang Zhang committed
60
    return _aggregate.apply(A, X, C)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
61
62

class _scaledL2(Function):
Hang Zhang's avatar
v0.1.0  
Hang Zhang committed
63
    @staticmethod
Hang Zhang's avatar
sync BN  
Hang Zhang committed
64
    def forward(ctx, X, C, S):
Zhang's avatar
v0.4.2  
Zhang committed
65
66
        if X.is_cuda:
            SL = lib.gpu.scaled_l2_forward(X, C, S)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
67
        else:
Zhang's avatar
v0.4.2  
Zhang committed
68
            raise NotImplemented
Hang Zhang's avatar
sync BN  
Hang Zhang committed
69
        ctx.save_for_backward(X, C, S, SL)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
70
        return SL
Hang Zhang's avatar
v0.1.0  
Hang Zhang committed
71
72

    @staticmethod
Hang Zhang's avatar
sync BN  
Hang Zhang committed
73
74
    def backward(ctx, gradSL):
        X, C, S, SL = ctx.saved_variables
Zhang's avatar
v0.4.2  
Zhang committed
75
76
        if X.is_cuda:
            gradX, gradC, gradS = lib.gpu.scaled_l2_backward(gradSL, X, C, S, SL)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
77
        else:
Zhang's avatar
v0.4.2  
Zhang committed
78
            raise NotImplemented
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
79
80
81
82
        return gradX, gradC, gradS


def scaledL2(X, C, S):
Zhang's avatar
v0.4.2  
Zhang committed
83
    r""" scaledL2 distance
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
84
85
86
87
88

    .. math::
        sl_{ik} = s_k \|x_i-c_k\|^2

    Shape:
Hang Zhang's avatar
sync BN  
Hang Zhang committed
89
90
91
92
        - Input: :math:`X\in\mathcal{R}^{B\times N\times D}`
          :math:`C\in\mathcal{R}^{K\times D}` :math:`S\in \mathcal{R}^K`
          (where :math:`B` is batch, :math:`N` is total number of features,
          :math:`K` is number is codewords, :math:`D` is feature dimensions.)
Hang Zhang's avatar
v1.0.1  
Hang Zhang committed
93
94
        - Output: :math:`E\in\mathcal{R}^{B\times N\times K}`
    """
Hang Zhang's avatar
v0.1.0  
Hang Zhang committed
95
    return _scaledL2.apply(X, C, S)