如何运行.py模块?

时间:2012-06-20 06:03:09

标签: python numpy scipy rdf factorization

我没有使用Python的经验。我查看了一些教程资料,但似乎很难理解高级代码。所以我来这里寻求更具体的答案。 对我来说,任务是重做计算机中的代码。

以下是该方案:

我是研究关系学习中的张量因子分解的研究生。论文[1]提供了运行该算法的代码,如下所示:

import logging, time
from numpy import dot, zeros, kron, array, eye, argmax
from numpy.linalg import qr, pinv, norm, inv 
from scipy.linalg import eigh
from numpy.random import rand

__version__ = "0.1" 
__all__ = ['rescal', 'rescal_with_random_restarts']

__DEF_MAXITER = 500
__DEF_INIT = 'nvecs'
__DEF_PROJ = True
__DEF_CONV = 1e-5
__DEF_LMBDA = 0

_log = logging.getLogger('RESCAL') 

def rescal_with_random_restarts(X, rank, restarts=10, **kwargs):
    """
    Restarts RESCAL multiple time from random starting point and 
    returns factorization with best fit.
    """
    models = []
    fits = []
    for i in range(restarts):
        res = rescal(X, rank, init='random', **kwargs)
        models.append(res)
        fits.append(res[2])
    return models[argmax(fits)]

def rescal(X, rank, **kwargs):
    """
    RESCAL 

    Factors a three-way tensor X such that each frontal slice 
    X_k = A * R_k * A.T. The frontal slices of a tensor are 
    N x N matrices that correspond to the adjecency matrices 
    of the relational graph for a particular relation.

    For a full description of the algorithm see: 
      Maximilian Nickel, Volker Tresp, Hans-Peter-Kriegel, 
      "A Three-Way Model for Collective Learning on Multi-Relational Data",
      ICML 2011, Bellevue, WA, USA

    Parameters
    ----------
    X : list
        List of frontal slices X_k of the tensor X. The shape of each X_k is ('N', 'N')
    rank : int 
        Rank of the factorization
    lmbda : float, optional 
        Regularization parameter for A and R_k factor matrices. 0 by default 
    init : string, optional
        Initialization method of the factor matrices. 'nvecs' (default) 
        initializes A based on the eigenvectors of X. 'random' initializes 
        the factor matrices randomly.
    proj : boolean, optional 
        Whether or not to use the QR decomposition when computing R_k.
        True by default 
    maxIter : int, optional 
        Maximium number of iterations of the ALS algorithm. 500 by default. 
    conv : float, optional 
        Stop when residual of factorization is less than conv. 1e-5 by default

    Returns 
    -------
    A : ndarray 
        array of shape ('N', 'rank') corresponding to the factor matrix A
    R : list
        list of 'M' arrays of shape ('rank', 'rank') corresponding to the factor matrices R_k 
    f : float 
        function value of the factorization 
    iter : int 
        number of iterations until convergence 
    exectimes : ndarray 
        execution times to compute the updates in each iteration
    """

    # init options
    ainit = kwargs.pop('init', __DEF_INIT)
    proj = kwargs.pop('proj', __DEF_PROJ)
    maxIter = kwargs.pop('maxIter', __DEF_MAXITER)
    conv = kwargs.pop('conv', __DEF_CONV)
    lmbda = kwargs.pop('lmbda', __DEF_LMBDA)
    if not len(kwargs) == 0:
        raise ValueError( 'Unknown keywords (%s)' % (kwargs.keys()) )

    sz = X[0].shape
    dtype = X[0].dtype 
    n = sz[0]
    k = len(X) 

    _log.debug('[Config] rank: %d | maxIter: %d | conv: %7.1e | lmbda: %7.1e' % (rank, 
        maxIter, conv, lmbda))
    _log.debug('[Config] dtype: %s' % dtype)

    # precompute norms of X 
    normX = [norm(M)**2 for M in X]
    Xflat = [M.flatten() for M in X]
    sumNormX = sum(normX)

    # initialize A
    if ainit == 'random':
        A = array(rand(n, rank), dtype=dtype)
    elif ainit == 'nvecs':
        S = zeros((n, n), dtype=dtype)
        T = zeros((n, n), dtype=dtype)
        for i in range(k):
            T = X[i]
            S = S + T + T.T
        evals, A = eigh(S,eigvals=(n-rank,n-1))
    else :
        raise 'Unknown init option ("%s")' % ainit

    # initialize R
    if proj:
        Q, A2 = qr(A)
        X2 = __projectSlices(X, Q)
        R = __updateR(X2, A2, lmbda)
    else :
        R = __updateR(X, A, lmbda)

    # compute factorization
    fit = fitchange = fitold = f = 0
    exectimes = []
    ARAt = zeros((n,n), dtype=dtype)
    for iter in xrange(maxIter):
        tic = time.clock()
        fitold = fit
        A = __updateA(X, A, R, lmbda)
        if proj:
            Q, A2 = qr(A)
            X2 = __projectSlices(X, Q)
            R = __updateR(X2, A2, lmbda)
        else :
            R = __updateR(X, A, lmbda)

        # compute fit value
        f = lmbda*(norm(A)**2)
        for i in range(k):
            ARAt = dot(A, dot(R[i], A.T))
            f += normX[i] + norm(ARAt)**2 - 2*dot(Xflat[i], ARAt.flatten()) + lmbda*(R[i].flatten()**2).sum()
        f *= 0.5

        fit = 1 - f / sumNormX
        fitchange = abs(fitold - fit)

        toc = time.clock()
        exectimes.append( toc - tic )
        _log.debug('[%3d] fit: %.5f | delta: %7.1e | secs: %.5f' % (iter, 
            fit, fitchange, exectimes[-1]))
        if iter > 1 and fitchange < conv:
            break
    return A, R, f, iter+1, array(exectimes)

def __updateA(X, A, R, lmbda):
    n, rank = A.shape
    F = zeros((n, rank), dtype=X[0].dtype)
    E = zeros((rank, rank), dtype=X[0].dtype)

    AtA = dot(A.T,A)
    for i in range(len(X)):
        F += dot(X[i], dot(A, R[i].T)) + dot(X[i].T, dot(A, R[i]))
        E += dot(R[i], dot(AtA, R[i].T)) + dot(R[i].T, dot(AtA, R[i]))
    A = dot(F, inv(lmbda * eye(rank) + E))
    return A

def __updateR(X, A, lmbda):
    r = A.shape[1]
    R = []
    At = A.T    
    if lmbda == 0:
        ainv = dot(pinv(dot(At, A)), At)
        for i in range(len(X)):
            R.append( dot(ainv, dot(X[i], ainv.T)) )
    else :
        AtA = dot(At, A)
        tmp = inv(kron(AtA, AtA) + lmbda * eye(r**2))
        for i in range(len(X)):
            AtXA = dot(At, dot(X[i], A)) 
            R.append( dot(AtXA.flatten(), tmp).reshape(r, r) )
    return R

def __projectSlices(X, Q):
    q = Q.shape[1]
    X2 = []
    for i in range(len(X)):
        X2.append( dot(Q.T, dot(X[i], Q)) )
    return X2

粘贴如此长的代码很无聊,但没有其他办法可以解决我的问题。对此我很抱歉。

我导入了这个模块并根据作者的website传递了参数:

import pickle, sys
from rescal import rescal

rank = sys.argv[1]
X = pickle.load('us-presidents.pickle')
A, R, f, iter, exectimes = rescal(X, rank, lmbda=1.0)

可以找到数据集us-presidents.rdf here

我的问题是:

  1. 根据代码注释,张量X是一个列表。我不太明白这一点,如何将列表与Python中的张量相关联?我能理解Python中的tensor = list吗?
  2. 我应该首先将RDF格式转换为三(主题,谓词,对象)格式吗?我不确定X的数据结构。如何手动将值赋值给X?
  3. 然后,如何运行它?
  4. 我未经他的授权粘贴作者的代码,这是侵权行为吗?如果是的话,我很抱歉,我很快就会删除它。

    问题可能有点无聊,但这对我来说很重要。任何帮助将不胜感激。

    [1] Maximilian Nickel,Volker Tresp,Hans-Peter Kriegel, 多关系数据集体学习的三向模型, 第28届国际机器学习大会论文集,2011年,美国华盛顿州贝尔维尤

2 个答案:

答案 0 :(得分:1)

要回答Q2:您需要转换RDF并保存它,然后才能从文件'us-presidents.pickle'加载它。该代码的作者可能曾经这样做过一次因为Python原生pickle格式加载速度更快。由于pickle格式包含数据的数据类型,X可能是一个numpy类实例,你可能需要这个代码使用的示例pickle文件,或者需要一些代码来执行pickle.dump如rescal期望的那样,如何从RDF转换为这个特定的pickle文件。

所以这可能会回答Q1:张量由一系列元素组成。从代码中可以看出,rescal的X参数具有长度(k = len(X))并且可以编入索引(T = X[i])。所以它的元素被用作一个列表(即使它可能是一些其他数据类型,它只是表现如此。

顺便说一下:如果您不熟悉Python并且只对计算结果感兴趣,那么您可能会获得更多帮助来联系软件作者。

答案 1 :(得分:1)

  
      
  1. 根据代码注释,张量X是一个列表。我不太明白这一点,如何将列表与Python中的张量相关联?我可以吗   了解Python中的tensor = list?
  2.   

不一定,但代码的作者已决定将张量数据表示为列表数据结构。如注释所示,列表X包含:

  

张量X的正面切片X_k列表。每个X_k的形状是('N','N')

这意味着张量被重复为元组列表:[(N, N), ..., (N, N)]

  
      
  1. 我不确定X的数据结构。如何手动将值赋值给X?
  2.   

现在我们现在是X的数据结构,我们可以使用赋值为它赋值。以下将元组(1, 3)分配给列表X中的第一个位置(因为第一个位置在索引0处,第二个位置在位置1处,等等):

X[0] = (1, 3)

类似地,以下内容将元组(2, 4)分配给第二个位置:

X[1] = (2, 4)