LU 분해(LU Decomposition)란? AI 행렬을 아래·위 삼각행렬로 나누는 방법
TL;DR
LU 분해(LU Decomposition)는 행렬을 아래 삼각행렬 L과 위 삼각행렬 U로 나누는 방법입니다. 실제 계산에서는 행을 바꾸는 부분 피벗팅을 함께 써서 순열 정보 P까지 다루는 경우가 많습니다. AI에서는 선형방정식 풀이, 행렬식 계산과 반복되는 수치 연산의 바탕이 됩니다. 다만 라이브러리마다 P의 정의와 반환 형식이 다르고, 특이행렬이나 상태가 나쁜 행렬에서는 결과를 따로 검증해야 합니다.
핵심 3줄 요약
- 핵심 1
행렬을 두 삼각행렬로 나눕니다. L은 대각선 아래, U는 대각선 위에 값이 남는 구조입니다. - 핵심 2
피벗팅이 계산을 지켜 줍니다. 작은 피벗을 피하려고 행을 바꾸며 그 순서를 P나 피벗 인덱스로 기록합니다. - 핵심 3
분해 뒤 여러 계산에 재사용합니다. 같은 계수행렬로 여러 우변을 풀 때 특히 유용하지만 역행렬을 직접 만드는 작업과는 다릅니다.
이 글에서 다룰 내용
- LU 분해의 한 문장 정의와 쉬운 계산 예시
- L·U·P와 부분 피벗팅이 맡는 역할
- 행렬 모양과 라이브러리 반환 형식 읽는 법
- QR·촐레스키·SVD·가우스 소거법과의 차이
- 선형방정식·행렬식·AI 수치 계산의 활용
- 재구성 오차와 해 잔차를 확인하는 순서
- 특이행렬·정밀도·자동미분의 주의점
LU 분해를 한 문장으로 정의하면 무엇인가요?
LU 분해는 행렬 A를 아래 삼각행렬 L과 위 삼각행렬 U의 곱으로 표현하고, 필요한 경우 행 교환을 순열행렬 P나 피벗 인덱스로 함께 기록하는 행렬 분해입니다.
아래 삼각행렬은 주대각선 위쪽 값이 0인 행렬입니다. 위 삼각행렬은 주대각선 아래쪽 값이 0입니다. 삼각행렬로 바꾸면 위에서 아래로 또는 아래에서 위로 값을 차례로 대입해 선형방정식을 풀 수 있습니다.
교과서에서는 A=LU처럼 간단히 쓰기도 합니다. 실무 함수는 수치적으로 더 안전한 부분 피벗팅을 적용하므로 P가 들어간 식을 반환하는 경우가 일반적입니다. SciPy와 JAX 문서는 A=P@L@U로 설명하고, TensorFlow 문서는 P@A=L@U로 설명합니다. 식이 달라 보이는 이유는 순열행렬을 정의하는 방향이 다르기 때문입니다.
한 줄 정리: LU 분해는 복잡한 행렬 계산을 순서대로 풀기 쉬운 두 삼각행렬 계산으로 바꿉니다.
쉬운 예시로 이해해 볼까요?
A가 두 행과 두 열을 가진 행렬이라고 해 보겠습니다. A의 첫째 행은 2, 1이고 둘째 행은 4, 3입니다. 이 행렬은 L의 첫째 행 1, 0과 둘째 행 2, 1, 그리고 U의 첫째 행 2, 1과 둘째 행 0, 1의 곱으로 나타낼 수 있습니다.
- A = [[2, 1], [4, 3]]
- L = [[1, 0], [2, 1]]
- U = [[2, 1], [0, 1]]
L과 U를 곱하면 첫째 행은 2, 1이고 둘째 행은 4, 3이 되어 A가 다시 나옵니다. 이 예시는 행을 바꾸지 않아도 되므로 P가 항등행렬입니다.
첫 피벗이 0이거나 매우 작다면 그대로 나눌 수 없거나 오차가 커질 수 있습니다. 이때 계산기는 더 적절한 행을 위로 올리고 교환 기록을 남깁니다. 그 기록이 순열행렬 P 또는 피벗 벡터입니다.
쉬운 예시: LU 분해는 한 번에 풀기 어려운 자물쇠를 아래 삼각 단계와 위 삼각 단계라는 두 순서로 나눠 여는 것과 비슷합니다.
왜 AI에서 LU 분해가 중요한가요?
선형방정식을 반복해서 풉니다
AI와 머신러닝의 수치 계산에는 A@x=b 형태가 자주 등장합니다. A를 한 번 LU 분해하면 새로운 b가 들어올 때마다 분해를 다시 하지 않고 전진 대입과 후진 대입으로 x를 구합니다. 같은 행렬에 여러 우변이 붙는 계산에서 재사용 가치가 큽니다.
고수준 선형대수 함수의 내부 기반이 됩니다
사용자가 항상 LU 함수를 직접 부르는 것은 아닙니다. 선형 시스템 풀이와 일부 행렬식 계산 같은 고수준 함수가 내부에서 LU 계열 알고리즘을 이용하기도 합니다. PyTorch 문서는 torch.linalg.solve가 lu_factor와 lu_solve의 조합이라고 설명합니다.
모델 계산의 수치 상태를 점검하게 합니다
분해 과정에서 U의 대각 원소가 0에 가까워지면 행렬이 특이하거나 수치적으로 풀기 어려울 가능성을 살필 수 있습니다. LAPACK DGETRF는 U의 특정 대각 원소가 정확히 0이면 분해는 끝났어도 선형 시스템 풀이에서 0으로 나누게 된다고 알립니다.
핵심 인사이트: LU 분해의 가치는 행렬을 보기 좋게 나누는 데만 있지 않습니다. 같은 행렬이 들어가는 여러 계산을 재사용 가능한 형태로 바꾸는 데 있습니다.
LU 분해는 어떤 순서로 작동하나요?
1. 피벗 열에서 기준 원소를 고릅니다
첫 열부터 계산을 시작해 대각선 위치의 피벗을 정합니다. 부분 피벗팅에서는 현재 열의 남은 행 가운데 절댓값이 큰 원소를 골라 피벗으로 씁니다. 필요한 행 교환은 순열 정보에 기록합니다.
2. 피벗 아래 원소를 없앱니다
피벗 아래의 값을 0으로 만들기 위해 각 행에서 피벗 행의 배수를 뺍니다. 이때 사용한 배수가 L의 대각선 아래에 저장됩니다. 소거 뒤 남은 위쪽 값은 U를 이룹니다.
3. 다음 대각선 위치에서 반복합니다
첫 열 아래를 정리하면 오른쪽 아래의 작은 부분행렬로 이동합니다. 같은 선택과 소거를 반복하면 L과 U가 완성됩니다. LAPACK DGETRF는 일반 M×N 행렬을 부분 피벗팅과 행 교환으로 분해합니다.
4. 삼각 시스템을 차례로 풉니다
A@x=b를 풀 때는 순열을 반영한 b를 먼저 L과 연결해 전진 대입으로 중간값 y를 구합니다. 이어 U@x=y를 후진 대입으로 풀어 x를 얻습니다. SciPy의 lu_solve는 lu_factor가 만든 압축 LU와 피벗을 받아 이 과정을 처리합니다.
실전 팁: 직접 역행렬을 만든 뒤 b에 곱하기보다 선형 시스템 풀이 함수를 쓰세요. 의도가 분명하며 불필요한 계산도 피합니다.
행렬 모양과 반환값은 어떻게 읽나요?
정사각행렬과 직사각행렬의 차이
SciPy와 JAX의 lu는 M×N 직사각행렬도 받습니다. K=min(M,N)일 때 L은 M×K, U는 K×N 모양입니다. TensorFlow tf.linalg.lu는 안쪽 두 차원이 M×M인 가역 정사각행렬을 요구합니다. 같은 LU라는 이름이라도 입력 조건부터 확인해야 합니다.
분리된 P·L·U와 압축 LU의 차이
scipy.linalg.lu는 P, L, U를 나눠 반환합니다. lu_factor와 torch.linalg.lu_factor는 L의 대각선 아래 부분과 U의 대각선 포함 위쪽 부분을 한 배열에 압축하고 피벗 인덱스를 따로 줍니다. L의 단위 대각선은 저장하지 않는 방식도 흔합니다.
배치 차원과 자료형의 차이
여러 행렬을 한 번에 분해하는 함수는 앞쪽 배치 차원을 허용합니다. TensorFlow는 float16·float32·float64와 복소수 자료형을 지원한다고 명시합니다. 지원 자료형, 장치, 피벗 옵션은 프레임워크와 버전에 따라 다르므로 함수 문서를 그대로 확인해야 합니다.
LU 분해와 헷갈리는 용어는 무엇이 다른가요?
가우스 소거법과 LU 분해의 차이
가우스 소거법은 행 연산으로 계수행렬을 삼각 형태로 바꾸고 해를 구하는 절차입니다. LU 분해는 그 소거 과정의 배수와 결과를 L과 U로 저장해 다시 쓰는 표현입니다. 같은 A로 여러 b를 풀 때 분해를 보관하는 이점이 드러납니다.
QR 분해와 LU 분해의 차이
QR 분해는 A를 직교·유니터리 행렬 Q와 위 삼각행렬 R로 나눕니다. LU는 아래·위 삼각행렬과 순열 정보를 사용합니다. 최소제곱 문제와 직교 기저가 핵심이면 QR이 자연스럽고, 일반 선형 시스템을 반복해서 풀 때는 LU가 널리 쓰입니다.
촐레스키 분해와 LU 분해의 차이
촐레스키 분해는 대칭 또는 에르미트 양의 정부호 행렬을 한 삼각행렬과 그 전치·켤레전치의 곱으로 나타냅니다. 조건을 만족하면 구조를 활용할 수 있지만 모든 정사각행렬에 쓸 수는 없습니다. LU는 더 일반적인 행렬을 다루되 피벗팅이 함께 등장합니다.
SVD와 LU 분해의 차이
특이값 분해는 직사각행렬을 두 직교·유니터리 행렬과 특이값으로 나눕니다. 랭크, 저랭크 근사와 조건을 분석하는 데 유용합니다. LU는 삼각 시스템 풀이와 재사용이 중심이며 특이값을 직접 제공하지 않습니다.
역행렬과 LU 분해의 차이
역행렬 A의 역은 A와 곱했을 때 항등행렬이 되는 행렬입니다. LU는 A를 계산하기 쉬운 인수로 나눈 결과입니다. 선형방정식 하나를 풀려고 역행렬 전체를 만들 필요는 없습니다. LU 기반 solve 함수는 필요한 해를 직접 구합니다.
비교 정리: LU는 일반 선형 시스템, QR은 직교화와 최소제곱, 촐레스키는 양의 정부호 구조, SVD는 랭크와 저랭크 구조를 볼 때 주로 선택합니다.
실전에서는 어디에 쓰이나요?
같은 행렬을 쓰는 여러 선형방정식
계수행렬 A는 같고 관측값이나 우변 b만 여러 개라면 LU 인수를 한 번 계산해 보관합니다. 이후 각 b마다 삼각 시스템만 풀면 됩니다. SciPy는 lu_factor의 결과를 lu_solve에 넘기는 인터페이스를 제공합니다.
행렬식의 부호와 크기 계산
삼각행렬 U의 행렬식은 대각 원소의 곱으로 구합니다. 여기에 L의 단위 대각선과 행 교환 횟수에 따른 부호를 반영해 A의 행렬식을 계산합니다. 값의 크기 범위가 크다면 곱을 그대로 계산하기보다 로그 절댓값 방식도 검토합니다.
AI 모델과 통계 계산의 내부 연산
회귀, 최적화, 확률 모델과 과학 계산에는 선형 시스템이 숨어 있습니다. 프레임워크가 고수준 연산 안에서 적절한 분해를 선택할 수 있으므로 사용자는 입력 행렬의 구조와 지원되는 미분 경로를 확인하는 편이 좋습니다.
CPU·GPU 수치 라이브러리의 기본 루틴
LAPACK의 GETRF 계열 루틴은 일반 행렬의 피벗 LU 분해를 제공합니다. SciPy lu_factor도 LAPACK GETRF의 래퍼라고 밝힙니다. 프레임워크의 함수 이름이 달라도 아래에서 비슷한 수치 선형대수 루틴을 연결하는 경우가 있습니다.
LU 분해 결과는 어떻게 확인하나요?
1. 입력 조건과 행렬 모양을 확인합니다
선택한 함수가 정사각행렬만 받는지, 직사각행렬도 받는지 먼저 봅니다. 배치 차원이 있다면 마지막 두 축이 행렬 축인지 확인합니다. NaN과 무한대가 들어간 입력도 미리 걸러야 합니다.
2. 순열 표기법을 문서와 맞춥니다
P가 실제 순열행렬인지 피벗 인덱스인지 확인합니다. A=P@L@U인지 P@A=L@U인지도 함수 문서의 식을 그대로 따릅니다. 이 방향을 거꾸로 쓰면 모양은 맞아도 재구성 결과가 달라집니다.
3. 원래 행렬을 재구성합니다
문서가 제시한 순서로 P, L, U를 곱해 A와 가까운지 확인합니다. 부동소수점 계산에서는 완전한 문자열 일치보다 허용 오차를 둔 allclose 방식이 알맞습니다. 오차가 크면 순열 방향과 축부터 다시 봅니다.
4. 해의 잔차를 계산합니다
선형방정식을 풀었다면 A@x-b의 크기를 확인합니다. 분해 재구성이 맞더라도 행렬 상태가 나쁘면 해가 입력 오차에 민감할 수 있습니다. 잔차와 함께 조건수, 정밀도와 문제의 허용 오차를 봅니다.
5. CPU와 GPU 결과를 비교합니다
자료형과 장치가 달라지면 마지막 자릿수와 선택된 피벗이 달라질 수 있습니다. 작은 검증 행렬로 재구성과 잔차를 비교하고, 허용 오차는 float16·float32·float64의 정밀도에 맞게 정합니다.
한 줄 정리: P의 정의, A 재구성 오차와 선형방정식 잔차를 함께 확인하면 LU 결과를 제대로 검증할 수 있습니다.
사용할 때 무엇을 주의해야 하나요?
첫째, 피벗 없는 A=LU만 가정하지 않습니다. 실제 함수는 행을 바꾸고 P나 피벗 벡터를 반환하기도 합니다. 이 정보를 빼고 L@U만 계산하면 원래 A와 행 순서가 달라집니다.
둘째, 특이행렬을 가역행렬처럼 풀지 않습니다. U 대각선에 0이 생기면 분해가 반환돼도 선형 시스템의 유일한 해를 구할 수 없습니다. 오류 코드와 예외, 대각 원소를 확인하세요.
셋째, 작은 잔차만 보고 문제를 끝내지 않습니다. 상태가 나쁜 행렬은 입력의 작은 변화가 해의 큰 변화로 이어질 수 있습니다. 조건수와 업무에서 허용하는 오차를 함께 살펴야 합니다.
넷째, 압축 LU 배열을 완성된 L로 읽지 않습니다. 배열의 아래쪽은 L의 일부이고 위쪽은 U입니다. 단위 대각선이 생략됐는지, 피벗 인덱스가 0부터 시작하는지도 문서에서 확인합니다.
다섯째, 자동미분과 장치 제약을 확인합니다. 분해 과정의 피벗 선택과 특이점 부근에서는 기울기가 불안정하거나 지원 조건이 제한될 수 있습니다. 모델 학습 경로에 넣기 전 사용하는 프레임워크의 미분·CUDA 설명을 읽으세요.
주의: LU 분해 함수가 오류 없이 끝났다는 사실만으로 선형방정식의 해가 믿을 만하다고 단정할 수 없습니다. 순열, 특이성, 조건수와 잔차를 따로 점검해야 합니다.
자주 묻는 질문
Q1. LU 분해는 모든 행렬에 가능한가요?
피벗팅을 포함한 LU 분해는 일반 정사각행렬과 여러 직사각행렬에 널리 적용됩니다. 다만 함수마다 입력 모양과 가역성 조건이 다릅니다. TensorFlow tf.linalg.lu는 가역 정사각행렬을 요구하지만 SciPy lu는 직사각행렬도 받습니다.
Q2. P는 왜 필요한가요?
0이거나 너무 작은 피벗을 피하려고 행을 바꾼 순서를 기록하기 위해 필요합니다. P를 빼면 L과 U를 곱한 행렬의 행 순서가 A와 다를 수 있습니다.
Q3. L의 대각선은 항상 1인가요?
많이 쓰이는 관례에서는 L의 대각선을 1로 두고 U가 피벗 값을 가집니다. 하지만 수학적 관례와 함수 반환 형식이 다를 수 있으므로 문서의 정의를 확인해야 합니다. 압축 형식은 L의 단위 대각선을 저장하지 않기도 합니다.
Q4. LU 분해로 역행렬을 구해도 되나요?
가능하지만 선형방정식의 해만 필요하다면 역행렬 전체를 만들 이유가 없습니다. LU 기반 solve 함수에 우변을 넘기는 편이 계산 의도와 검증 방법이 더 분명합니다.
Q5. QR 분해 대신 LU 분해를 언제 쓰나요?
일반 정사각 계수행렬로 선형방정식을 풀고 같은 분해를 여러 우변에 재사용하려면 LU가 자연스러운 선택입니다. 최소제곱 문제, 직교 기저와 수치 안정성이 더 중요하다면 QR이나 SVD가 알맞을 수 있습니다.
출처
마무리
LU 분해는 행렬을 아래 삼각행렬 L과 위 삼각행렬 U로 나누고, 행 교환이 필요하면 순열 정보 P를 함께 기록하는 방법입니다. 선형방정식 풀이와 행렬식 계산, 수치 라이브러리의 기본 연산을 이해하는 데 중요한 개념입니다.
처음에는 L과 U의 모양보다 P의 방향을 놓치기 쉽습니다. 사용하는 함수가 제시한 식으로 A를 재구성하고 A@x-b의 잔차를 확인하세요. 특이행렬과 조건수, 자료형까지 함께 확인하면 LU 분해 결과를 AI 계산에 적용하기가 한결 안전합니다.
