Il y avait peu d'exemples d'utilisation autres que les réseaux neuronaux et le Deep Learning dans les articles liés à TensorFlow, j'ai donc implémenté la décomposition matricielle non négative (NMF) à titre d'exemple.
OS: Ubuntu 14.04 CPU: Core i7-3770 3.40GHz×8 Mémoire: 16 Go TersorFlow: mode CPU ver.0.6.0 Python version: 2.7
NMF est un algorithme qui se rapproche de la matrice de valeurs non négatives V par le produit de deux matrices de valeurs non négatives H et W. Il est utilisé dans un large éventail de domaines tels que l'extraction d'entités, la réduction de dimension, le traitement d'images comme méthode de regroupement et le langage naturel.
Entrée: $ V \ in \ mathcal {R} ^ {m \ times n} _ {+}, \ r \ in \ mathcal {N} ^ + $
production:$\underset{W,H} {\arg\min} ||V-WH||_{F}^{2}\ \ s.t.\ W \in \mathcal{R} _{+} ^{m \times r}, H \in \mathcal{R} _{+} ^ {r \times n} $
Cette fois, nous utiliserons la règle de mise à jour multiplicative la plus simple pour optimiser NMF. L'algorithme MU exécute alternativement les expressions de mise à jour suivantes jusqu'à ce qu'elles convergent.
H_{a\mu} \leftarrow H_{a\mu}\frac{(W^TV)_{a\mu}}{(W^TWH)_{a\mu}},\ \
W_{ia} \leftarrow W_{ia}\frac{(VH^T)_{ia}}{(WHH^T)_{ia}}
Lien de référence: Algorithms for Non-negative Matrix Factorization
Le corps de la classe est implémenté comme suit.
tfnmf.py
# -*- coding: utf-8 -*-
from __future__ import division
import numpy as np
import tensorflow as tf
class TFNMF(object):
"""Non-negative Matrix Factorization by TensorFlow"""
def __init__(self, V, rank):
#Conversion de matrice Numpy en Tensor of TensorFlow
V_ = tf.constant(V, dtype=tf.float32)
shape = V.shape
#Sqrt moyen(V.mean() / rank)Échelle à un nombre aléatoire uniforme
scale = 2 * np.sqrt(V.mean() / rank)
initializer = tf.random_uniform_initializer(maxval=scale)
#Matrice H,Génération de variables W
self.H = H = tf.get_variable("H", [rank, shape[1]],
initializer=initializer)
self.W = W = tf.get_variable(name="W", shape=[shape[0], rank],
initializer=initializer)
#Enregistrer W pour le jugement de convergence
W_old = tf.get_variable(name="W_old", shape=[shape[0], rank])
self._save_W = W_old.assign(W)
#Algorithme MU
#Mettre à jour H
Wt = tf.transpose(W)
WV = tf.matmul(Wt, V_)
WWH = tf.matmul(tf.matmul(Wt, W), H)
WV_WWH = WV / WWH
with tf.device('/cpu:0'):
#Convertit un élément contenant nan de 0% en 0
WV_WWH = tf.select(tf.is_nan(WV_WWH),
tf.zeros_like(WV_WWH),
WV_WWH)
H_new = H * WV_WWH
self._update_H = H.assign(H_new)
#Mettre à jour W(H a été mis à jour)
Ht = tf.transpose(H)
VH = tf.matmul(V_, Ht)
WHH = tf.matmul(W, tf.matmul(H, Ht))
VH_WHH = VH / WHH
with tf.device('/cpu:0'):
#Convertit un élément contenant nan de 0% en 0
WV_WWH = tf.select(tf.is_nan(WV_WWH),
tf.zeros_like(WV_WWH),
WV_WWH)
W_new = W * VH_WHH
self._update_W = W.assign(W_new)
#Changement total de chaque élément de W
self._delta = tf.reduce_sum(tf.abs(W_old - W))
def run(self, sess, max_iter=200):
tf.initialize_all_variables().run()
for i in range(max_iter):
sess.run(self._save_W)
H, _ = sess.run([self.H, self._update_H])
W, _ = sess.run([self.W, self._update_W])
delta = sess.run(self._delta)
if delta < 0.001:
break
return W, H
Mesurez le temps d'exécution en modifiant le nombre de cœurs utilisés par le CPU. L'entrée est une matrice aléatoire de 10000 x 10000 et le nombre de rangs est de 10.
Le script d'exécution est le suivant.
main.py
# -*- coding: utf-8 -*-
from __future__ import print_function
import time
import numpy as np
import tensorflow as tf
from tfnmf import TFNMF
def main():
V = np.random.rand(10000,10000)
rank = 10
num_core = 8
tfnmf = TFNMF(V, rank)
config = tf.ConfigProto(inter_op_parallelism_threads=num_core,
intra_op_parallelism_threads=num_core)
with tf.Session(config=config) as sess:
start = time.time()
W, H = tfnmf.run(sess)
print("Computational Time: ", time.time() - start)
#Calcul de l'erreur carrée
W = np.mat(W)
H = np.mat(H)
error = np.power(V - W * H, 2).sum()
print("Reconstruction Error: ", error)
if __name__ == '__main__':
main()
C'est le résultat lorsqu'il est exécuté avec 8 cœurs. L'erreur de reconstruction représente l'erreur au carré, qui est la fonction objectif.
$python main.py
I tensorflow/core/common_runtime/local_device.cc:40] Local device intra op parallelism threads: 8
I tensorflow/core/common_runtime/direct_session.cc:58] Direct session inter op parallelism threads: 8
Computational Time: 45.2025268078
Reconstruction Error: 8321195.31013
C'est un graphique du temps d'exécution lorsque le nombre de cœurs passe de 1 à 8.
Huit cœurs sont environ 1,4 fois plus rapides qu'un cœur. La surcharge était plus importante que ce à quoi je m'attendais, et même si j'augmentais le nombre de cœurs, le temps d'exécution n'a pas augmenté de façon spectaculaire. Ce n'est peut-être pas une méthode très efficace pour faire sess.run () chaque fois que W et H sont mis à jour.
Cette fois, j'ai utilisé TensorFlow uniquement pour le calcul matriciel, donc j'ai senti que ce n'était pas utile, mais c'est merveilleux de pouvoir décrire facilement le calcul parallèle. La prochaine fois, j'essaierai d'implémenter la décomposition tensorielle.
Recommended Posts