-
Notifications
You must be signed in to change notification settings - Fork 0
/
get_tsne.m
154 lines (124 loc) · 3.94 KB
/
get_tsne.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
% t-SNE, gradiente descendente com momento:
% learn_rate = Taxa de importância para o gradiente.
% n_iter = Núm. iterações. | Dim = Dimensões a serem usadas.
% dx = Matriz de distâncias (NxN).
% n_momento = Núm. de gradientes anteriores a serem usados no momento.
% X = Matriz com os vetores otimizados (NxDim).
% J = Função de custo.
function [X_final,J] = get_tsne(Dim, px)
lr = 10; % learn_rate = Taxa de importância para o gradiente.
n_iter = 1000; % Núm. de iterações.
n_momento = 20;
% Normalização, é importante, mas depende muito dos dados.
px = 1e-3*((px-min(px(:)))/(max(px(:))-min(px(:))));
px(px==0) = eps; % Evita que haja elementos com probabilidade zero.
N = size(px,1); % Núm. de vetores.
% Inicialização aleatória da observação inicial.
X = 1e-3*randn(N,Dim);
m = 1;
s = 1:n_momento;
g = 1;
momento = zeros(N,Dim,n_momento+1);
tic;
qx = get_qx(X); % Calcula o q(i,j).
qx(qx==0) = eps; % Evita que haja elementos com probabilidade zero.
for ite = 1:n_iter
X_final = X;
for k = 1:N % Para todos os vetores.
d_prev = repmat(X(k,:),N,1) - X;
d_prev = sqrt(diag(d_prev*d_prev')).^2;
mat_temp = repmat(X(k,:),N,1);
grad = -lr*gradiente(mat_temp, X, px(k,:), qx(k,:), d_prev, k);
momento(k,:,m) = X(k,:) + grad;
if ite > n_momento
m_coef = 0.99;
for c = abs(-n_momento:-1)
% Decaimento exponencial (os mais próximos tem pesos maiores).
momento(k,:,c) = (1-m_coef)^s(g) * momento(k,:,c);
g = g+1;
end
g = 1;
% Soma dos gradientes anteriores (em decaimento exponencial).
m_sum = sum(momento(k,:,1:end-1),3);
X(k,:) = X(k,:) + m_coef*grad + m_sum;
else
X(k,:) = X(k,:) + grad;
end
end
m = m+1;
if ~mod(ite,n_momento+1)
m = 1;
end
qx = get_qx(X); % Calcula o q(i,j).
qx(qx==0) = eps;
% Calcula o custo em cada iteração.
J(ite) = sum(sum(px.*log(px./qx)));
% Caso o custo atual seja menor que o anterior, atuliza o X_final.
if ite > 1
if abs(J(ite)) < abs(J(ite-1))
X_final = X;
end
end
% Testa se o custo está parado, se estiver, para o laço for.
if ite > 2
if J(ite) == J(ite-1) || abs(J(ite)) < 0.0001 || abs(J(ite)) > 2*abs(J(ite-1))
break;
end
end
clc;
fprintf('Iteração: %d/%d', ite, n_iter);
end
fprintf('\n');
toc;
% Plota a curva da derivada, normalizada entre 0 e 1.
J = abs(J);
plot(J/max(J),'b'); grid on; title('Custo'); xlabel('Iterações');
hold on;
qx = get_qx(X_final); % Calcula o q(i,j).
qx(qx==0) = eps;
c_f = sum(sum(px.*log(px./qx)));
plot(ite, abs(c_f)/max(J),'ro');
disp(abs(J(ite)/max(J)));
end
% Determnia o gradiente
% X, Y = Observações com n dimensões;
function res = gradiente(X, Y, px, qx, d_prev, k)
d_prev = (1+d_prev.^2).^-1;
d_prev(k) = 0;
a = X-Y;
b = (px-qx)';
b = b.*d_prev;
res = zeros(size(a,1),size(a,2));
for i = 1:size(a,2)
res(:,i) = 4*(a(:,i).*b);
end
res = sum(res,1);
end
% Determina o denominador do q(i,j).
function res = get_dij(X)
N = size(X,1);
res = 0;
for i = 1:N
% Determina o denominador do q(i,j) para cada vetor X(i,:).
mat_temp = repmat(X(i,:),N,1) - X;
mat_temp = sqrt(diag(mat_temp*mat_temp'));
mat_temp = (1+mat_temp.^2).^-1;
mat_temp(i) = 0;
res = res + sum(mat_temp);
end
end
% Determina o q(i,j).
function qx = get_qx(X)
N = size(X,1);
p2 = get_dij(X);
qx = zeros(N);
for i = 1:N
% Determina o calculo do q(i,j) para cada vetor X(i,:).
mat_temp = repmat(X(i,:),N,1) - X;
mat_temp = sqrt(diag(mat_temp*mat_temp'));
mat_temp = (1+mat_temp.^2).^-1;
mat_temp(i) = 0;
mat_temp = mat_temp./p2;
qx(i,:) = mat_temp;
end
end