Это выдержка из восьмого раздела главы 2 книги Глубокое обучение с Tensorflow 2.0.
Разложение по сингулярным значениям (SVD) — еще один способ разложения матрицы на сингулярные векторы и сингулярные значения. SVD позволяет нам обнаруживать ту же информацию, что и собственное разложение, однако SVD более широко применим. Каждая вещественная матрица имеет разложение по сингулярным значениям, но это не так для разложения по собственным значениям. СВД можно записать так:
A = UDV^T
Предположим, что A является матрицей mxn, тогда U определяется как матрица вращения mxm, D — матрица масштабирования и проецирования матрицы mxn, а V — матрица вращения nxn.
Каждая из этих матриц имеет особую структуру. Матрицы U и V определены как ортогональные матрицы U^T = U^(-1) и V^T = V^(-1). Матрица D определяется как диагональная матрица.
Элементы по диагонали D называются сингулярными значениями матрицы A. Столбцы U известны как лево-сингулярные векторы. Столбцы V известны как правосингулярные векторы.
# mxn matrix A svd_matrix_A = tf.constant([[2, 3], [4, 5], [6, 7]], dtype=tf.float32) print(“Matrix A: \n{}\n”.format(svd_matrix_A)) # Using tf.linalg.svd to calculate the singular value decomposition where d: Matrix D, u: Matrix U and v: Matrix V d, u, v = tf.linalg.svd(svd_matrix_A, full_matrices=True, compute_uv=True) print(“Diagonal D: \n{} \n\nMatrix U: \n{} \n\nMatrix V^T: \n{}”.format(d, u, v)) Matrix A: [[2. 3.] [4. 5.] [6. 7.]] Diagonal D: [11.782492 0.41578525] Matrix U: [[ 0.30449855 -0.86058956 0.40824753] [ 0.54340035 -0.19506174 -0.81649673] [ 0.78230214 0.47046405 0.40824872]] Matrix V^T: [[ 0.63453555 0.7728936 ] [ 0.7728936 -0.63453555]] # Lets see if we can bring back the original matrix from the values we have # mxm orthogonal matrix U svd_matrix_U = tf.constant([[0.30449855, -0.86058956, 0.40824753], [0.54340035, -0.19506174, -0.81649673], [0.78230214, 0.47046405, 0.40824872]]) print(“Orthogonal Matrix U: \n{}\n”.format(svd_matrix_U)) # mxn diagonal matrix D svd_matrix_D = tf.constant([[11.782492, 0], [0, 0.41578525], [0, 0]], dtype=tf.float32) print(“Diagonal Matrix D: \n{}\n”.format(svd_matrix_D)) # nxn transpose of matrix V svd_matrix_V_trans = tf.constant([[0.63453555, 0.7728936], [0.7728936, -0.63453555]], dtype=tf.float32) print(“Transpose Matrix V: \n{}\n”.format(svd_matrix_V_trans)) # UDV(^T) svd_RHS = tf.tensordot(tf.tensordot(svd_matrix_U, svd_matrix_D, axes=1), svd_matrix_V_trans, axes=1) predictor = tf.reduce_all(tf.equal(tf.round(svd_RHS), svd_matrix_A)) def true_print(): print(“It WORKS. \nRHS: \n{} \n\nLHS: \n{}”.format(tf.round(svd_RHS), svd_matrix_A)) def false_print(): print(“Condition FAILED. \nRHS: \n{} \n\nLHS: \n{}”.format(tf.round(svd_RHS), svd_matrix_A)) tf.cond(predictor, true_print, false_print) Orthogonal Matrix U: [[ 0.30449855 -0.86058956 0.40824753] [ 0.54340035 -0.19506174 -0.81649673] [ 0.78230214 0.47046405 0.40824872]] Diagonal Matrix D: [[11.782492 0. ] [ 0. 0.41578525] [ 0. 0. ]] Transpose Matrix V: [[ 0.63453555 0.7728936 ] [ 0.7728936 -0.63453555]] It WORKS. RHS: [[2. 3.] [4. 5.] [6. 7.]] LHS: [[2. 3.] [4. 5.] [6. 7.]]
Матрицу A можно рассматривать как линейное преобразование. Это преобразование можно разложить на три подпреобразования:
1. Вращение,
2. Изменение масштаба и проецирование,
3. Вращение.
Эти три шага соответствуют трем матрицам U, D и V.
Давайте посмотрим, как происходят эти преобразования по порядку.
# Let’s define a unit square svd_square = tf.constant([[0, 0, 1, 1],[0, 1, 1, 0]], dtype=tf.float32) # a new 2x2 matrix svd_new_matrix = tf.constant([[1, 1.5], [0, 1]]) # SVD for the new matrix new_d, new_u, new_v = tf.linalg.svd(svd_new_matrix, full_matrices=True, compute_uv=True) # lets’ change d into a diagonal matrix new_d_marix = tf.linalg.diag(new_d) # Rotation: V^T for a unit square plot_transform(svd_square, tf.tensordot(new_v, svd_square, axes=1), “$Square$”, “$V^T \cdot Square$”, “Rotation”, axis=[-0.5, 3.5 , -1.5, 1.5]) plt.show() # Scaling and Projecting: DV^(T) plot_transform(tf.tensordot(new_v, svd_square, axes=1), tf.tensordot(new_d_marix, tf.tensordot(new_v, svd_square, axes=1), axes=1), “$V^T \cdot Square$”, “$D \cdot V^T \cdot Square$”, “Scaling and Projecting”, axis=[-0.5, 3.5 , -1.5, 1.5]) plt.show() # Second Rotation: UDV^(T) trans_1 = tf.tensordot(tf.tensordot(new_d_marix, new_v, axes=1), svd_square, axes=1) trans_2 = tf.tensordot(tf.tensordot(tf.tensordot(new_u, new_d_marix, axes=1), new_v, axes=1), svd_square, axes=1) plot_transform(trans_1, trans_2,”$U \cdot D \cdot V^T \cdot Square$”, “$D \cdot V^T \cdot Square$”, “Second Rotation”, color=[‘#1190FF’, ‘#FF9A13’], axis=[-0.5, 3.5 , -1.5, 1.5]) plt.show()
Вышеупомянутые подпреобразования можно найти для каждой матрицы следующим образом:
- U соответствует собственным векторам AA^T
- V соответствует собственным векторам A^TA
- D соответствует собственным значениям AA^T или A^TA, которые совпадают.
В качестве упражнения попробуйте доказать, что это так.
Возможно, наиболее полезной функцией SVD является то, что мы можем использовать ее для частичного обобщения обращения матриц на неквадратные матрицы, как мы увидим в следующем разделе.
Вы можете прочитать этот раздел и следующие темы:
- 02.01 — Скаляры, векторы, матрицы и тензоры
- 02.02 — Умножение матриц и векторов
- 02.03 — Тождественные и обратные матрицы
- 02.04 — Линейная зависимость и размах
- 02.05 — Нормы
- 02.06 — Специальные виды матриц и векторов
- 02.07 — Собственное разложение
- 02.08 — Разложение по сингулярным числам
- 02.09 — Псевдоинверсия Мура-Пенроуза
- 02.10 — Оператор трассировки
- 02.11 — Определяющая
- 02.12 — Пример: анализ основных компонентов
на Глубокое обучение с TF 2.0: 02.00-Линейная алгебра. Вы можете получить код этой статьи и остальной части главы здесь. Ссылки на блокнот в Google Colab и Jupyter Binder находятся в конце блокнота.