[ad_1]
importer date-heure
importer flux tenseur comme tf
importer matplotlib.pyplot comme plt
importer numpy comme np
importer engourdi
définitivement tSNE(X, ndims=2, perplexité=30, la graine=0, max_iter=500, stop_lying_iter=100, maman_switch_iter=400):
“”“L’algorithme t-SNE
Arguments :
X : les coordonnées de grande dimension
ndims : nombre de dimensions dans le domaine de sortie
Retour:
Points de X en petite dimension
““”
élan = 0,5
final_momentum = 0,8
eta = 200,0
N, _RÉ = X.façonner
np.Aléatoire.la graine(la graine)
# normaliser l’entrée
X -= X.moyenne(axe=0) # zéro moyenne
X /= np.abdos(X).maximum() # mise à l’échelle min-max
# calcule la similarité d’entrée pour le t-SNE exact
P = calculGaussienPerplexité(X, perplexité)
# symétriser et normaliser les similarités d’entrée
P = P + P.J
P /= P.somme()
# mentir sur les P-values
P *= 12.0
# initialise la solution
Oui = np.Aléatoire.Randn(N, ndims) * 0,0001
# effectuer la boucle d’entraînement principale
gains = np.ceux_comme(Oui)
uY = np.zeros_like(Oui)
pour je dans Portée(max_iter):
# calculer le gradient, mettre à jour les gains
dY = calculateExactGradient(P, Oui)
gains = np.où(np.signe(dY) != np.signe(uY), gains+0,2, gains*0,8).agrafe(0,1)
# mise à jour du gradient avec élan et gains
uY = élan * uY – eta * gagne * dY
Oui = Oui + uY
# faire de la solution une moyenne nulle
Oui -= Oui.moyenne(axe=0)
# Arrêtez de mentir sur les valeurs P après un certain temps et changez de rythme
si je == stop_lying_iter:
P /= 12.0
si je == maman_switch_iter:
élan = final_élan
# progression de l’impression
si (je % 50) == 0:
C = évaluerErreur(P, Oui)
à présent = date-heure.date-heure.à présent()
imprimer(F“{maintenant} – Itération {i} : Erreur = {C}”)
retourner Oui
@engourdi.foutre(nopython=Vrai)
définitivement calculateExactGradient(P, Oui):
“”“Gradient de la fonction de coût t-SNE
Arguments :
P : matrice de similarité
Y : coordonnées de faible dimension
Retour:
dY, un tableau numérique de forme (N,D)
““”
N, _RÉ = Oui.façonner
# calcule la matrice de distance euclidienne au carré de Y, la matrice Q et la somme de normalisation
JJ = calculateSquaredEuclideanDistance(Oui)
Q = 1/(1+JJ)
somme_Q = Q.somme()
# calculer le gradient
multiple = (P – (Q/somme_Q)) * Q
dY = np.zeros_like(Oui)
pour n dans Portée(N):
pour m dans Portée(N):
si n==m: Continuez
dY[n] += (Oui[n] – Oui[m]) * multiple[n,m]
retourner dY
@engourdi.foutre(nopython=Vrai)
définitivement évaluerErreur(P, Oui):
“”“Évaluer la fonction de coût t-SNE
Arguments :
P : matrice de similarité
Y : coordonnées de faible dimension
Retour:
Erreur t-SNE totale C
““”
JJ = calculateSquaredEuclideanDistance(Oui)
# Calculer la matrice Q et la somme de normalisation
Q = 1/(1+JJ)
np.fill_diagonal(Q, np.trouver(np.float32).eps)
Q /= Q.somme()
# Somme erreur t-SNE : somme P log(P/Q)
Erreur = P * np.Journal( (P + np.trouver(np.float32).eps) / (Q + np.trouver(np.float32).eps) )
retourner Erreur.somme()
@engourdi.foutre(nopython=Vrai)
définitivement calculGaussienPerplexité(X, perplexité):
“”“Calculer la perplexité gaussienne
Arguments :
X : tableau numpy de forme (N,D)
perplexité : double
Retour:
Matrice de similarité P
““”
# Calculer la matrice de distance euclidienne au carré
N, _RÉ = X.façonner
JJ = calculateSquaredEuclideanDistance(X)
# Calculer le noyau gaussien ligne par ligne
P = np.zeros_like(JJ)
pour n dans Portée(N):
trouvé = Faux
bêta = 1.0
min_beta = –np.inf
max_beta = np.inf
tol = 1e–5
# itérer jusqu’à obtenir une bonne perplexité
nitre = 0
pendant que ne pas trouvé et nitre < 200:
# calcule la ligne du noyau gaussien
P[n] = np.exp(–bêta * JJ[n])
P[n,n] = np.trouver(np.float32).eps
# calcule l’entropie de la ligne courante
# Gaussiens à normaliser en ligne pour en faire une probabilité
# alors H = somme_i -P[i] log(P[i])
# = somme_i -P[i] (-bêta * DD[n] – log(somme_P))
# = somme_i P[i] * bêta * DD[n] + log(somme_P)
puisard = P[n].somme()
H = bêta * (JJ[n] @ P[n]) / puisard + np.Journal(puisard)
# Évaluer si l’entropie est dans le niveau de tolérance
Hdiff = H – np.log2(perplexité)
si –tol < Hdiff < tol:
trouvé = Vrai
Pause
si Hdiff > 0:
min_beta = bêta
si max_beta dans (np.inf, –np.inf):
bêta *= 2
autre:
bêta = (bêta + max_beta) / 2
autre:
max_beta = bêta
si min_beta dans (np.inf, –np.inf):
bêta /= 2
autre:
bêta = (bêta + min_beta) / 2
nitre += 1
# normaliser cette ligne
P[n] /= P[n].somme()
affirmer ne pas np.isnan(P).quelconque()
retourner P
@engourdi.foutre(nopython=Vrai)
définitivement calculateSquaredEuclideanDistance(X):
“”“Calculer la distance au carré
Arguments :
X : tableau numpy de forme (N,D)
Retour:
tableau numpy de forme (N,N) de distances au carré
““”
N, _RÉ = X.façonner
JJ = np.des zéros((N,N))
pour je dans Portée(N–1):
pour j dans Portée(je+1, N):
différence = X[i] – X[j]
JJ[j][i] = JJ[i][j] = différence @ différence
retourner JJ
(X_train, y_train), (X_test, y_test) = tf.keras.ensembles de données.mnist.load_data()
# choisir 1 000 échantillons dans l’ensemble de données
Lignes = np.Aléatoire.choix(X_test.façonner[0], 1000, remplacer=Faux)
X_données = X_train[rows].remodeler(1000, –1).astype(“flotter”)
X_label = y_train[rows]
# exécutez t-SNE pour transformer en 2D et visualiser en nuage de points
Oui = tSNE(X_données, 2, 30, 0, 500, 100, 400)
plt.chiffre(taille de figue=(8,8))
plt.dispersion(Oui[:,0], Oui[:,1], c=X_label)
plt.Afficher()