Étant donné le tenseur suivant (qui est le résultat d'un réseau [notez le grad_fn]):
ll = torch.zeros((1,243)) for x in xx: ll[0,x.long()] += 1
Que nous définirons comme:
tvtensor = torch.tensor([i for i in range(243)]).unsqueeze(1).repeat(1,xx.shape[0]).float().requires_grad_(True) (xx==tvtensor).sum(dim=1)
Je voudrais définir une opération qui compte le nombre d'occurrences de chaque valeur de telle manière que l'opération produise le tenseur suivant:
tt = [] for i in range(243): tt.append((xx == i).unsqueeze(0)) torch.cat(tt,dim=0).sum(dim=1)
c'est-à-dire qu'il y a 2 zéros, 1 un, 2 treize, etc ... le nombre total de valeurs possibles est défini en amont, mais dans cet exemple est 243
Jusqu'à présent, j'ai essayé les approches suivantes, qui produisent avec succès le tenseur souhaité, mais ne le font pas d'une manière qui permette de calculer les gradients à travers le réseau:
tensor([2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1])
xx = torch.tensor([121., 241., 125., 1., 108., 238., 125., 121., 13., 117., 121., 229., 161., 13., 0., 202., 161., 121., 121., 0., 121., 121., 242., 125.]).requires_grad_(True)
EDIT: tentative ajoutée
- Je ne m'attendais pas vraiment à ce que cela soutienne un accessoire, mais je pensais que j'essaierais quand même
tensor([121., 241., 125., 1., 108., 238., 125., 121., 13., 117., 121., 229., 161., 13., 0., 202., 161., 121., 121., 0., 121., 121., 242., 125.], grad_fn=<MvBackward>)
Toute aide est appréciée
EDIT: Comme demandé, l'objectif final est le suivant:
J'utilise une technique pour calculer la similitude structurelle entre deux séquences temporelles. L'un est réel et l'autre est généré. La technique est décrite dans cet article ( https://link.springer.com/chapter/10.1007/978-3-642-02279-1_33 ) où une série chronologique est convertie en une séquence de mots de code et la distribution de mots de code (similaire à la façon dont Bag of Words est utilisé en PNL) est utilisé pour représenter la série chronologique. Deux séries sont considérées comme similaires lorsque les deux distributions de signaux sont similaires. C'est à cela que sert le tenseur des statistiques de comptage.
Ce que l'on souhaite, c'est pouvoir construire une fonction de perte qui consomme ce tenseur et mesure la distance entre le signal réel et le signal généré (la norme euclidienne sur les données du domaine temporel directement ne fonctionne pas bien et cette approche revendique de meilleurs résultats), de sorte qu'elle peut mettre à jour le générateur de manière appropriée.
3 Réponses :
Vous ne pourrez pas faire cela car une opération unique
est simplement non différentiable.
De plus, seuls les tenseurs à floating
peuvent avoir un gradient tel qu'il est défini uniquement pour le domaine des nombres réels, pas pour les entiers.
Pourtant, il peut y avoir une autre façon différentiable de faire ce que vous voulez réaliser, mais c'est une question différente.
Ok donc cela explique pourquoi les tentatives ne fonctionnent pas car elles utilisent des opérateurs de comparaison qui, comme elles produisent des entiers, n'auraient pas de grad_fn? Y a-t-il une manière différentiable dont vous pouvez penser qui pourrait produire un résultat équivalent?
Cela dépend de votre objectif final (je suppose qu'il ne prend pas de valeurs uniques). Comme décrit ci-dessus, on pourrait combiner des fonctions différentiables afin d'obtenir une approximation de ce que vous recherchez. Cependant, ce n'est généralement pas nécessaire et vous pourrez peut-être éviter la non-différentiabilité d'une manière ou d'une autre. Veuillez décrire votre objectif final, nous pourrons peut-être vous aider.
L'opération "uniquify" n'est pas différentiable, mais il peut y avoir des moyens d'y remédier, par exemple, en écrivant un opérateur personnalisé, ou par une combinaison intelligente d'opérateurs différentiables.
Cependant, vous devez vous poser cette question: quel est selon vous le gradient d'une telle opération? Ou, à un niveau supérieur, qu'essayez-vous de réaliser avec cette opération?
La sortie fait partie d'un modèle génératif, et le tenseur que j'ai montré ci-dessus est le résultat d'une opération qui est une version codifiée d'un signal généré. Les statistiques de comptage représentent le nombre d'occurrences de différents codes au sein du signal généré et sont dans ce cadre représentatives de la qualité du signal. Par conséquent, les gradients que je recherche seraient par rapport aux changements dans le nombre d'occurrences de chaque valeur dans le tenseur.
Je ne suis pas sûr de comprendre votre cas d'utilisation, mais cela ne semble pas être quelque chose avec des dégradés bien définis. Ce que vous décrivez, ce ne sont que des différences, c'est-à-dire des dérivés dans le cas discret, et je ne pense pas que ce soit quelque chose d'optimisable par le type de techniques offertes par les bibliothèques DL traditionnelles.
J'imagine que vous essayez de contraindre le modèle à générer un certain nombre de signaux spécifiques. Dans ce cas, vous souhaiterez peut-être explorer certains modèles de génération contrôlée. Je ne suis pas un expert en la matière, mais une idée générale pourrait être d'attacher un classificateur à la sortie et de lui demander de classer le nombre d'occurrences pour un signal spécifique, puis d'ajouter un terme de pénalité basé sur la prédiction.