이미지 데이터에 대해 행렬 곱셈 분해를 시도해 보았다.

27572 단어 수학.tech
최근에 저는 매트릭스 형식으로 장량을 표현하는 방법을 배웠기 때문에 연습하는 동시에 매트릭스 형식으로 적당한 이미지를 표현하고 데이터를 압축하고 싶습니다.
이미지 가져오기
먼저 적절한 이미지를 출력합니다.
import numpy as np
from numpy.linalg import svd, matrix_rank

from PIL import Image
img = Image.open('smile-1.png')
gray_img = img.convert('L')
gray_img.save('smile_mono.png')
a = np.asarray(gray_img)

여기에 상기 256*256 행렬을 행렬의 곱셈 형식으로 분해하고 특이성 값을 분해하여 낮은 등급의 근사성을 진행한다.
엄격히 행렬 곱셈의 형식으로 표시하다
여기, 아래와 같이 8개의 행렬 곱셈의 형식으로 표시한다.대열의 모습은 전혀 보이지 않지만, 아래 발의 색인을 고정시키고 가로로 뻗은 장량의 발을 하나의 뿌리로 간주하면 대열은 일렬로 늘어선다
보입니다.

행렬 적은 예를 들어 왼쪽부터 순서대로 특이치 분해를 반복하고 왼쪽부터 작은 행렬을 생성한다.아래에서 말한 바와 같이 기이한 값 분해를 통해 작은 행렬을 왼쪽과 오른쪽의 큰 행렬로 나눈다.이후 이 절차를 오른쪽으로 반복하면 행렬을 한 열로 배열하는 상술한 표시를 할 수 있다.
이 오른쪽 매트릭스와 왼쪽 매트릭스 사이를 연결하는 비트는 중간에서 가장 크고 가장자리에 가까워지면서 작은 값을 얻는다.

코드를 어떻게 표시합니까?이쪽 자료(https://github.com/utokyo-qsw/joint-seminar)
'1Q84'를 참조하여 제작하게 해주세요.
#8つのテンソルに分解し、テンソルの添字を0から順に並び替える。
a_tensor = a.reshape(4,4,4,4,4,4,4,4)
a_tensor = a_tensor.transpose(0,1,2,3,4,5,6,7).reshape(4,4,4,4,4,4,4,4)
행렬 곱셈으로 분해한다.
a_tensor.reshape(4,4**7)
u1, s1, vh1 = svd(a_tensor.reshape(4, 4**7),full_matrices=False)
M1 = u1
u2, s2, vh2 = svd((np.diag(s1) @ vh1).reshape(4**2, 4**6),full_matrices=False)
M2 = u2.reshape(4,4,4**2)
u3, s3, vh3 = svd((np.diag(s2) @ vh2).reshape(4**3, 4**5),full_matrices=False)
M3 = u3.reshape(4**2,4,4**3)
u4, s4, vh4 = svd((np.diag(s3) @ vh3).reshape(4**4, 4**4), full_matrices=False)
M4 = u4.reshape(4**3,4,4**4)
u5, s5, vh5 = svd((np.diag(s4) @ vh4).reshape(4**5, 4**3),full_matrices=False)
M5 = u5.reshape(4**4,4,4**3)
u6, s6, vh6 = svd((np.diag(s5) @ vh5).reshape(4**4, 4**2),full_matrices=False)
M6 = u6.reshape(4**3,4,4**2)
u7, s7, vh7 = svd((np.diag(s6) @ vh6).reshape(4**3, 4),full_matrices=False)
M7 = u7.reshape(4**2,4,4)
M8 = np.diag(s7) @ vh7
def reconstruct_matrix(M1,M2,M3,M4,M5,M6,M7,M8):
  matrix = np.einsum("ab,bcd,def,fgh,hij,jkl,lmn,no -> acegikmo",M1,M2,M3,M4,M5,M6,M7,M8,optimize=True).reshape(4,4,4,4,4,4,4,4).transpose(0,1,2,3,4,5,6,7).reshape(256,256)
  return matrix
W_h_reconstructed = reconstruct_matrix(M1,M2,M3,M4,M5,M6,M7,M8)
img3 = Image.fromarray(np.uint8(W_h_reconstructed))
img3.save('smile_mono_MPS_8site.jpg')

원본 이미지는 완전히 재현할 수 있습니다.
이미지 데이터 압축
여기에는 압축 행렬 곱셈의 가로 차원을 통해 어떤 근사성을 진행한다.본드 차원(행렬의 좌우 발의 차원)을 최대 16으로 제한한 것이다.이렇게 되면 데이터가 압축되고 벡터와 행렬의 연산이 빨라지는 등 장점이 있다.
chi_max = 16

## M1 と M2をつなぐボンド
chi_12 = min(chi_max,M1.shape[1])
## M2 と M3をつなぐボンド
chi_23 = min(chi_max,M2.shape[2])
## M3 と M4をつなぐボンド
chi_34 = min(chi_max,M3.shape[2])

## M4 と M5をつなぐボンド
chi_45 = min(chi_max,M4.shape[2])
## M5 と M6をつなぐボンド
chi_56 = min(chi_max,M5.shape[2])
## M6 と M7をつなぐボンド
chi_67 = min(chi_max,M6.shape[2])
## M7 と M8をつなぐボンド
chi_78 = min(chi_max,M7.shape[2])

M1_ap = M1[:,:chi_12]
M2_ap = M2[:chi_12,:,:chi_23]
M3_ap = M3[:chi_23,:,:chi_34]
M4_ap = M4[:chi_34,:,:chi_45]
M5_ap = M5[:chi_45,:,:chi_56]
M6_ap = M6[:chi_56,:,:chi_67]
M7_ap = M7[:chi_67,:,:chi_78]
M8_ap = M8[:chi_78,:]

W_h_ap = reconstruct_matrix(M1_ap,M2_ap,M3_ap,M4_ap,M5_ap,M6_ap,M7_ap,M8_ap)

np.linalg.norm(W_h_reconstructed  - W_h_ap)/np.linalg.norm(W_h_reconstructed )
# 0.054004230487981635

img4 = Image.fromarray(np.uint8(W_h_ap))
img4.save('smile_mono_MPS_8site_approx_.jpg')

Bond 차원이 가장 큰 중앙의 특이값이 되는 직사각형을 보여 주려고 할 때, 이 그림에 대해 다음과 같은 쇠퇴 경향을 관찰했다.
norm_e = s4**2

# 規格化した特異値
x = s4/np.sqrt(norm_e.sum())
import matplotlib.pyplot as plt
plt.plot(x) 
plt.savefig("s")

총결산
행렬 곱셈 분해를 이미지 데이터에 적용해 보십시오.특이치 분해와 비교, 임의로 장량을 바꿀 때의 발과 정밀도 비교, 다른 이미지에도 적용해 보는 등 재미있어 보인다.
참고 자료
https://github.com/utokyo-qsw

좋은 웹페이지 즐겨찾기