Сейчас мы объединим наши слова с первыми 10 000 слов из всего нашего словаря (некоторые слова уже есть в нём), и создадим матрицу встраивания.
embeddings = np.concatenate((vecs[my_word_indices], vecs[:10000,:]), axis=0); embeddings.shape
# (10030, 100)
Слова имеют 100 измерений, и нам нужен способ визуализировать их в трёхмерном пространстве.
Мы будем использовать метод главных компонент (PCA), который широко используется и имеет множество применений, включая визуализацию многомерных данных в более низком измерении!
from collections import defaultdict
from sklearn import decomposition
components = get_components(embeddings, categories, my_word_indices)
plotly_3d(components.T[:len(my_words),:], categories, "pca.html")
# (30, 10030)
IFrame('pca.html', width=600, height=400)
Принцип Джонсона-Линденштрауса: в высоком пространстве можно вложить небольшое количество точек в пространство с меньшей размерностью таким образом, что расстояния между точками сохраняются (это доказывается с помощью случайной проекции).
Полезно иметь возможность уменьшить размерность данных, сохраняя при этом расстояния. Принцип Джонсона-Линденштрауса является классическим результатом такого типа.
embeddings.shape
# (10030, 100)
rand_proj = embeddings @ np.random.normal(size=(embeddings.shape[1], 40)); rand_proj.shape
# (10030, 40)
# pca = decomposition.PCA(n_components=3).fit(rand_proj.T)
# components = pca.components_
components = get_components(rand_proj, categories, my_word_indices)
plotly_3d(components.T[:len(my_words),:], categories, "pca-rand-proj.html")
# (30, 10030)
IFrame('pca-rand-proj.html', width=600, height=400)
Наша цель сегодня:
Давайте используем данные из задачи BMC 2012 по удалению фона, видео 003.
Импортируем необходимые библиотеки:
import imageio
imageio.plugins.ffmpeg.download()
import moviepy.editor as mpe
import numpy as np
import scipy
%matplotlib inline
import matplotlib.pyplot as plt
scale = 0.50 # adjust the ratio to change the resolution of the image
dims = (int(240 * scale), int(320 * scale))
fps = 60 # frames per second
M = np.load("movie/med_res_surveillance_matrix_60fps.npy")
print(dims, M.shape)
# (120, 160) (19200, 6000)
plt.imshow(np.reshape(M[:,140], dims), cmap='gray');
plt.figure(figsize=(12, 12))
plt.imshow(M, cmap='gray')
# <matplotlib.image.AxesImage at 0x7f601f315fd0>
В будущем вы можете загрузить сохранённое содержимое:
U = np.load("U.npy")
s = np.load("s.npy")
V = np.load("V.npy")
Что такое U
, S
и V
?
U.shape, s.shape, V.shape
# ((19200, 6000), (6000,), (6000, 6000))
Проверяем, являются ли они разложением M
.
reconstructed_matrix = U @ np.diag(s) @ V
np.allclose(M, reconstructed_matrix)
# True
Да.
low_rank = np.expand_dims(U[:,0], 1) * s[0] * np.expand_dims(V[0,:], 0)
plt.figure(figsize=(12, 12))
plt.imshow(low_rank, cmap='gray')
# <matplotlib.image.AxesImage at 0x7f1cc3e2c9e8>
plt.imshow(np.reshape(low_rank[:,0], dims), cmap='gray');
Как получить человека на переднем плане?
plt.imshow(np.reshape(M[:,0] - low_rank[:,0], dims), cmap='gray');
s
— диагональная матрица с диагональными элементами.
np.set_printoptions(suppress=True, precision=4)
import timeit
import pandas as pd
m_array = np.array([100, int(1e3), int(1e4)])
n_array = np.array([100, int(1e3), int(1e4)])
index = pd.MultiIndex.from_product([m_array, n_array], names=['# rows', '# cols'])
pd.options.display.float_format = '{:,.3f}'.format
df = pd.DataFrame(index=m_array, columns=n_array)
# %%prun
for m in m_array:
for n in n_array:
A = np.random.uniform(-40,40,[m,n])
t = timeit.timeit('np.linalg.svd(A, full_matrices=False)', number=3, globals=globals())
df.set_value(m, n, t)
df/3
100 | 1000 | 10000 | |
---|---|---|---|
100 | 0,006 | 0,009 | 0,043 |
1000 | 0,004 | 0,259 | 0,992 |
10000 | 0,019 | 0,984 | 218,726 |
Отлично! Но...
Недостаток: это действительно медленно (мы отбросили много вычислений).
%time u, s, v = np.linalg.svd(M, full_matrices=False)
'''
CPU times: user 5min 38s, sys: 1.53 s, total: 5min 40s
Wall time: 57.1 s
'''
M.shape
# (19200, 6000)
Идея: давайте попробуем использовать меньшую матрицу!
Мы ещё не нашли лучшего универсального метода SVD, поэтому мы просто используем метод, который мы использовали для небольших матриц, матрицы примерно того же размера, что и исходная.
def simple_randomized_svd(M, k=10):
m, n = M.shape
transpose = False
if m < n:
transpose = True
M = M.T
rand_matrix = np.random.normal(size=(M.shape[1], k)) # short side by k
Q, _ = np.linalg.qr(M @ rand_matrix, mode='reduced') # long side by k
smaller_matrix = Q.T @ M # k by short side
U_hat, s, V = np.linalg.svd(smaller_matrix, full_matrices=False)
U = Q @ U_hat
if transpose:
return V.T, s.T, U.T
else:
return U, s, V
%time u, s, v = simple_randomized_svd(M, 10)
**CPU times: user 3.06 s, sys: 268 ms, total: 3.33 s
Wall time: 789 ms**
U_rand, s_rand, V_rand = simple_randomized_svd(M, 10)
low_rank = np.expand_dims(U_rand[:,0], 1) * s_rand[0] * np.expand_dims(V_rand[0,:], 0)
plt.imshow(np.reshape(low_rank[:,0], dims), cmap='gray');
Мы как получаем людей?
Как этот метод работает?
```py
rand_matrix = np.random.normal(size=(M.shape[1], 10))
rand_matrix.shape
# (6000, 10)
plt.imshow(np.reshape(rand_matrix[:4900,0], (70,70)), cmap='gray');
temp = M @ rand_matrix; temp.shape
# (19200, 10)
plt.imshow(np.reshape(temp[:,0], dims), cmap='gray');
plt.imshow(np.reshape(temp[:,1], dims), cmap='gray');
Q, _ = np.linalg.qr(M @ rand_matrix, mode='reduced'); Q.shape
# (19200, 10)
np.dot(Q[:,0], Q[:,1])
# -3.8163916471489756e-17
plt.imshow(np.reshape(Q[:,0], dims), cmap='gray');
plt.imshow(np.reshape(Q[:,1], dims), cmap='gray');
smaller_matrix = Q.T @ M; smaller_matrix.shape
# (10, 6000)
U_hat, s, V = np.linalg.svd(smaller_matrix, full_matrices=False)
U = Q @ U_hat
plt.imshow(np.reshape(U[:,0], dims), cmap='gray');
Реконструируем маленькую матрицу:
reconstructed_small_M = U @ np.diag(s) @ V
И получаем человека.
plt.imshow(np.reshape(M[:,0] - reconstructed_small_M[:,0], dims), cmap='gray');
Сравнение времени:
from sklearn import decomposition
import fbpca
Полный SVD:
%time u, s, v = np.linalg.svd(M, full_matrices=False)
'''
CPU times: user 5min 38s, sys: 1.53 s, total: 5min 40s
Wall time: 57.1 s
'''
Наш (переупрощённый) randomized_svd:
%time u, s, v = simple_randomized_svd(M, 10)
'''
CPU times: user 2.37 s, sys: 160 ms, total: 2.53 s
Wall time: 641 ms
'''
Sklearn:
%time u, s, v = decomposition.randomized_svd(M, 10)
'''
CPU times: user 19.2 s, sys: 1.44 s, total: 20.7 s
Wall time: 3.67 s
'''
Я бы выбрал fbpca, потому что он быстрее sklearn и более надёжен и точен, чем наша упрощённая реализация.
Вот результаты Facebook Research:
Время и точность в зависимости от k:
import timeit
import pandas as pd
U_rand, s_rand, V_rand = fbpca.pca(M, 700, raw=True)
reconstructed = U_rand @ np.diag(s_rand) @ V_rand
np.linalg.norm(M - reconstructed)
# 1.1065914828881536e-07
plt.imshow(np.reshape(reconstructed[:,140], dims), cmap='gray');
pd.options.display.float_format = '{:,.2f}'.format
k_values = np.arange(100,1000,100)
df_rand = pd.DataFrame(index=["time", "error"], columns=k_values)
# df_rand = pd.read_pickle("svd_df")
for k in k_values:
U_rand, s_rand, V_rand = fbpca.pca(M, k, raw=True)
reconstructed = U_rand @ np.diag(s_rand) @ V_rand
df_rand.set_value("error", k, np.linalg.norm(M - reconstructed))
t = timeit.timeit('fbpca.pca(M, k)', number=3, globals=globals())
df_rand.set_value("time", k, t/3)
df_rand.to_pickle("df_rand")
df_rand
100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 1000 | |
---|---|---|---|---|---|---|---|---|---|---|
time | 2.07 | 2.57 | 3.45 | 6.44 | 7.99 | 9.02 | 10.24 | 11.70 | 13.30 | 10.87 |
error | 58,997.27 | 37,539.54 | 26,569.89 | 18,769.37 | 12,559.34 | 6,936.17 | 0.00 | 0.00 | 0.00 | 0.00 |
df = pd.DataFrame(index=["error"], columns=k_values)
for k in k_values:
reconstructed = U[:,:k] @ np.diag(s[:k]) @ V[:k,:]
df.set_value("error", k, np.linalg.norm(M - reconstructed))
df.to_pickle("df")
fig, ax1 = plt.subplots()
ax1.plot(df.columns, df_rand.loc["time"].values, 'b-', label="randomized SVD time")
ax1.plot(df.columns, np.tile([57], 9), 'g-', label="SVD time")
ax1.set_xlabel('k: # of singular values')
# Make the y-axis label, ticks
В этом тексте описывается процесс работы с матрицами и их разложениями с использованием различных методов и библиотек. Текст содержит фрагменты кода на языке Python, а также результаты вычислений и сравнения времени выполнения различных алгоритмов. **Метод randomized_range_finder находит ортогональную матрицу, диапазон которой приблизительно равен диапазону матрицы A (шаг 1 нашего алгоритма).**
Для этого мы используем LU и QR разложения, которые рассмотрим позже.
Я использовал исходный код sklearn.extmath.randomized_svd в качестве руководства.
```py
# Вычисление ортогональной матрицы, диапазон которой примерно равен диапазону A
# power_iteration_normalizer может быть safe_sparse_dot (быстрый, но нестабильный), LU (средний) или QR (медленный, но наиболее точный)
def randomized_range_finder(A, size, n_iter=5):
Q = np.random.normal(size=(A.shape[1], size))
for i in range(n_iter):
Q, _ = linalg.lu(A @ Q, permute_l=True)
Q, _ = linalg.lu(A.T @ Q, permute_l=True)
Q, _ = linalg.qr(A @ Q, mode='economic')
return Q
Здесь представлен наш метод случайного SVD.
def randomized_svd(M, n_components, n_oversamples=10, n_iter=4):
n_random = n_components + n_oversamples
Q = randomized_range_finder(M, n_random, n_iter)
print(Q.shape)
# проецируем M на (k + p)-мерное пространство с использованием базисных векторов
B = Q.T @ M
print(B.shape)
# вычисляем SVD на тонкой матрице: ширина (k + p)
Uhat, s, V = linalg.svd(B, full_matrices=False)
del B
U = Q @ Uhat
print(U.shape)
return U[:, :n_components], s[:n_components], V[:n_components, :]
u, s, v = randomized_svd(vectors, 5)
Тест:
vectors.shape
# (2034, 26576)
Q = np.random.normal(size=(vectors.shape[1], 10)); Q.shape
# (26576, 10)
Q2, _ = linalg.qr(vectors @ Q, mode='economic'); Q2.shape
# (2034, 10)
Q2.shape
# (2034, 10)
Конец теста:
%time u, s, v = randomized_svd(vectors, 5)
'''
CPU times: user 136 ms, sys: 0 ns, total: 136 ms
Wall time: 137 ms
'''
u.shape, s.shape, v.shape
# ((2034, 5), (5,), (5, 26576))
show_topics(v)
'''
['jpeg image edu file graphics images gif data',
'edu graphics data space pub mail 128 3d',
'space jesus launch god people satellite matthew atheists',
'space launch satellite commercial nasa satellites market year',
'image data processing analysis software available tools display']
'''
Чтобы вычислить ошибку разложения при изменении количества тем, необходимо написать цикл и построить график результатов.
plt.plot(range(0,n*step,step), error)
# [<matplotlib.lines.Line2D at 0x7fe3f8a1b438>]
%time u, s, v = decomposition.randomized_svd(vectors, 5)
'''
CPU times: user 144 ms, sys: 8 ms, total: 152 ms
Wall time: 154 ms
'''
%time u, s, v = decomposition.randomized_svd(vectors.todense(), 5)
'''
CPU times: user 2.38 s, sys: 592 ms, total: 2.97 s
Wall time: 2.96 s
'''
Дополнительные ресурсы:
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )