[AI 인공지능 머신러닝 딥러닝/Julia] - Julia 프로그래밍 - 언어 및 강의 소개
Julia 프로그래밍 - 언어 및 강의 소개
Julia 프로그래밍 언어줄리아(Julia)는 고성능의 수치 해석 및 계산과학의 필요 사항을 만족시키면서 일반 목적 프로그래밍에도 효과적으로 사용될 수 있도록 설계된 고급 동적 프로그래밍 언어이
inner-game.tistory.com
[AI 인공지능 머신러닝 딥러닝/Julia] - Julia 프로그래밍 - Julia 설치
Julia 프로그래밍 - Julia 설치
이전 글[AI 인공지능 머신러닝 딥러닝/Julia] - Julia 프로그래밍 - 언어 및 강의 소개 Julia 프로그래밍 - 언어 및 강의 소개Julia 프로그래밍 언어줄리아(Julia)는 고성능의 수치 해석 및 계산과학의 필
inner-game.tistory.com

범위
이해력
인덱싱
조회수
유형 프로모션 ⁽⁺⁾
--유형 프로모션 피하기
행렬
N차원 배열
--수동 정의 ⁽⁺⁾
--연결 및 재구성
기본 작업
이해력
인덱싱 및 뷰
특수 배열 생성자
--0과 1
--사전 할당 행렬 ⁽⁺⁾
기타 배열 유형 ⁽⁺⁾
--SparseArrays.jl
--오프셋어레이.jl
--StaticArrays.jl
배열 반복
행렬 곱셈
점곱
단위 행렬
Iterables에서 샘플링
분포에서의 샘플링
이전 강의에서 벡터에 대해 이미 소개했지만, 자세한 설명은 하지 않았습니다. 벡터는 대괄호 안에 쉼표로 구분된 값으로 정의된다는 점을 기억하세요.

v1 = [1, 2, 3, 4, 5]
Julia에서 벡터는 단지 1차원 배열일 뿐입니다.
Vector{Int64} (alias for Array{Int64, 1})
typeof(v1)
요소 유형
벡터는 모든 요소 유형에 대해 생성될 수 있습니다. 이 유형은 다음 메서드를 사용하여 확인할 수 있습니다 eltype.
Int64
eltype(v1)

v2 = ['a', 'b', 'c']
Vector{Char} (alias for Array{Char, 1})
typeof(v2)
Char
eltype(v2)
벡터를 생성할 때 벡터의 유형을 지정할 수도 있습니다. 이는 일반적으로 특정 유형의 빈 벡터를 생성하는 데 사용됩니다.

v3 = Float16[1, 2, 3]

v4 = Char[]
Vector{Float16} (alias for Array{Float16, 1})
typeof(v3)
Vector{Char} (alias for Array{Char, 1})
typeof(v4)
기본 기능
다음을 사용하여 배열의 차원 수를 확인할 수 있습니다 ndims.
1
ndims(v1) # a vector as a 1-dimensional array.
length벡터의 다음을 검사할 수 있습니다 .
5
length(v1)
배열 의 는 size차원의 튜플입니다. 벡터의 경우, 다음 길이를 포함하는 싱글톤 튜플을 반환합니다.

size(v1)
또한 메모리 크기를 바이트 단위로 확인할 수 있습니다.
40
sizeof(v1) # 5 Int64s => 5 * 64 bit = 5 * 8 bytes = 40 bytes
범위
지난주에 이미 범위를 소개했습니다. 범위를 수집하면 다음과 같은 벡터가 생성됩니다.

v5 = collect(1:5)
Vector{Int64} (alias for Array{Int64, 1})
typeof(v5)
벡터를 정의하는 방법으로 이해력도 도입했습니다.

v6 = [sqrt(x) for x in 1:10]

v7 = [sqrt(x) for x in 1:10 if x % 2 == 0]
대괄호 표기법을 사용하여 벡터를 색인할 수 있습니다.
이 목적을 위해 1~10까지의 값을 갖는 작은 테스트 벡터를 만들어 보겠습니다.

one_to_ten = collect(1:10)
경고:
줄리아의 지수는 수학적 표기법에 맞게 1부터 시작한다는 점을 명심하세요!
2
one_to_ten[2] # second entry
4
one_to_ten[4] # fourth entry

one_to_ten[2:4] # second until fourth entries
3
4
one_to_ten[begin+2:end-6] # relative indexing
// 1+2부터 10-6까지 한것, 즉 3:4

one_to_ten[4:-1:2] # iterate in reverse
// 4 to 2 and reverse(-1)라는 뜻
1
3
5
one_to_ten[[1, 3, 5]] # index values at specific positions 1, 3, 5
인덱싱은 원본과 독립적인 새로운 벡터를 메모리에 할당합니다(복사본을 만듭다).
begin
x1 = collect(1:10)
y1 = x1[2:4] # copy part of x1 into new vector y1
@info y1
@info x1
y1[1] = 42 # modify first entry in y1 to be 42
@info y1 # y1 has changed 🟧
@info x1 # x1 hasn't changed 🟪
end

// 즉, x1은 바뀌지 않았고, y1 에 인덱싱해서 새로 생긴 메모리만 바뀌었다.
메모리가 새로 생기는 것을 원치 않으면 아래의 Views를 이용하면 된다.
배열의 복사본을 만드는 것은 모든 항목을 메모리에 기록해야 하므로 속도가 느립니다. 대신 뷰를 사용하여 메모리에 있는 관련 데이터에 대한 "창"을 제공할 수 있습니다.

view(one_to_ten, 2:4)
매크로를 사용하면 @view이전에 도입된 인덱스 표기법을 사용할 수 있습니다.

@view one_to_ten[2:4]

@view one_to_ten[begin+1:end-6]
뷰는 다음 유형입니다 SubArray.
SubArray{Int64, 1, Vector{Int64}, Tuple{UnitRange{Int64}}, true}
typeof(@view one_to_ten[2:4])
뷰를 수정하면 원래 배열도 수정됩니다.
begin
x2 = collect(1:10)
y2 = @view x2[2:4] # create view onto x2
@info y2
@info x2
y2[1] = 42 # modify first entry in y2 to be 42
@info y2 # y2 has changed 🟧
@info x2 # x2 ALSO changed! 🟧
end

팁
메서드에 많은 호출이 필요한 경우 함수, 루프 또는 블록에서 매크로(추가로 ) @view 를 사용하여 해당 메서드 내부의 모든 인덱싱 작업을 뷰로 전환할 수도 있습니다! @views begin ... end
예: 이전 코드 블록은 다음과 같이 작성될 수 있습니다.
@views begin # every indexing operation in this code block will create a view
x2 = collect(1:10)
y2 = x2[2:4] # creates view onto x2 due to @views
y2[1] = 42
end
"대괄호 구문"을 사용하여 배열을 직접 생성할 때, 대괄호 안의 인수는 유형이 승격됩니다. 이는 구현 세부 사항으로 볼 수 있지만, 이 동작을 알아두는 것이 좋습니다.
모든 입력에 공통된 프로모션 유형이 있는 경우 해당 유형은 배열입니다 eltype. 그렇지 않은 경우 는 다음과 eltype같습니다 Any.
v8 = [1.0, 2.3, 0.8]
v8 = [1, 2.3, 4//5]
Vector{Float64} (alias for Array{Float64, 1})
typeof(v8)
일부 유형 조합에는 공통된 프로모션 유형이 없습니다. 이로 인해 다음과 같은 결과가 발생합니다 Vector{Any}.
does_not_promote = ["String", 1.4]
does_not_promote = ["String", 1.4]
Vector{Any} (alias for Array{Any, 1})
typeof(does_not_promote)
--유형 프로모션 피하기
유형 프로모션이 필요하지 않은 경우 명시적으로 생성하십시오.Vector{Any}
v9 = [1, 2.3, 4//51]
v9 = Any[1, 2.3, 4//5]
Any
eltype(v9)
[Int64, Float64, Rational{Int64}]
typeof.(v9)
// typeof.(v9)는 broadcast(typeof, v9)의 축약형이며, 즉 v9의 각 원소마다 typeof 함수를 적용한다는 뜻입니다.
// 만약 점(.)을 빼고 typeof(v9)라고 하면, 전체 배열 v9의 타입인 Vector{Any} 하나만 반환합니다.
또는 튜플을 사용하세요:
t1 = [1, 2.3, 4//5]
t1 = (1, 2.3, 4//5)
Tuple{Int64, Float64, Rational{Int64}}
typeof(t1)
팁
성능상의 이유로 다음과 같은 유형의 벡터는 피하는 것이 가장 좋습니다 Vector{Any}. Julia 컴파일러는 요소 유형을 추론할 수 없으므로 코드를 특수화할 수 없어 성능이 저하됩니다.
변환 및 프로모션에 대한 Julia 문서 에서 유형 프로모션에 대한 자세한 내용을 확인할 수 있습니다 .
// 줄리아는 처음에 컴파일할때 런된다. 그래서 타입을 미리 알면 코드를 최적화 시켜 둔다.
// 그런데 애니를 하면 이때 결정을 못하고 나중에 런할때 하나씩 다 살펴보고 결정하기 때문에 느리다.
// 이 최적화는 타입프로모션의 이유 이기도 하다.
우리는 방금 벡터가 1차원 배열이라는 것을 배웠습니다 .
2차원 배열 을 행렬이라고 합니다 . 행렬은 대괄호와 원하는 연결 유형을 나타내는 추가 기호를 사용하여 정의됩니다.
• 수평 연결( 열 방향 ): 공백, 탭 및 이중 세미콜론;;
• 수직 연결( 행 방향 ): 줄 바꿈 및 세미콜론;
이러한 조합을 통해 행렬과 블록 행렬을 정의하는 방법은 여러 가지가 있습니다. 다음은 두 가지 일반적인 예입니다.
M1 = 2×2 Matrix{Int64}:
1 2
3 4
M1 = [1 2; 3 4] # spaces between entries in row, semicolon between rows
M2 = 2×2 Matrix{Int64}:
1 2
3 4
M2 = [
1 2 # spaces between entries in row
3 4 # newline between rows
]
차원이 3 이상인 배열을 텐서라고 합니다.
--수동 정의 ⁽⁺⁾
큰 텐서를 직접 작성해야 하는 경우는 거의 없지만 Julia는 이에 대한 구문을 제공 합니다 .;1차원과 2차원에서 concatenate 와 마찬가지로 ;;, 세미콜론을 더 많이 사용하면 동일한 일반적인 체계가 확장됩니다. 구분 기호의 세미콜론 개수는 특정 차원을 지정하므로, ;;;3차원 ;;;;, 4차원 등에서 concatenates를 사용합니다.
// don't do this, below
A1 = 2×2×1×2 Array{Int64, 4}:
[:, :, 1, 1] =
1 2
3 4
[:, :, 1, 2] =
5 6
7 8
A1 = [[1 2; 3 4];;;; [5 6; 7 8]] # concatenate two 2x2 matrices in the fourth dimension
--연결 및 재구성
훨씬 더 쉬운 방법은 배열을 catcon cat enate 하는 것입니다.
A2 = 2×2×2 Array{Int64, 3}:
[:, :, 1] =
1 2
3 4
[:, :, 2] =
1 2
3 4
A2 = cat(M1, M2; dims=3) # concatenate two 2x2 matrices in the third dimension
또는 배열과 범위를 재구성하려면:
2×3×3 reshape(::UnitRange{Int64}, 2, 3, 3) with eltype Int64:
[:, :, 1] =
1 3 5
2 4 6
[:, :, 2] =
7 9 11
8 10 12
[:, :, 3] =
13 15 17
14 16 181
reshape(1:18, 2, 3, 3)
// ( input, 2 x 3 x 3 ) 라는 뜻
이 reshape함수는 재구성하려는 차원만큼 많은 매개변수를 사용합니다.
예를 들어, 배열을 재구성하려면모양을 만들다 A를 p x q x r x s, 부르다 reshape(A, p, q, r, s).
이전에 살펴본 연산 eltype, length, 는 모든 유형의 배열에 대해 정의되어 있습니다.sizeA
2×3 Matrix{Int64}:
1 2 3
4 5 6
A = [1 2 3; 4 5 6]
Int64
eltype(A)
(2, 3)
size(A)
3
size(A, 2) # size along second dimension
6
length(A) # number of elements in matrix
2
ndims(A) # number of dimensions
3×2 Matrix{Int64}:
1 5
4 3
2 6
reshape(A, 3, 2)
이해는 벡터뿐만 아니라 모든 차원의 배열을 정의하는 데 사용할 수 있습니다.
5×5 Matrix{Complex{Int64}}:
1+6im 1+7im 1+8im 1+9im 1+10im
2+6im 2+7im 2+8im 2+9im 2+10im
3+6im 3+7im 3+8im 3+9im 3+10im
4+6im 4+7im 4+8im 4+9im 4+10im
5+6im 5+7im 5+8im 5+9im 5+10im
[complex(r, i) for r in 1:5, i in 6:10]
3×10×2 Array{Int64, 3}:
[:, :, 1] =
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10 11
[:, :, 2] =
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10 11
3 4 5 6 7 8 9 10 11 12
[x + y + z for x in 0:2, y in 0:9, z in 0:1]
// 앞에 보이는 [:, :, 1] 부분이 z = 0 z=0인 경우의 2차원 배열 뒤에 보이는 [:, :, 2] 부분이 z = 1 z=1인 경우의 2차원 배열입니다. 각 원소는 x + y + z x+y+z로 계산된 값이 맞습니다.
이해는 Number 유형에만 사용할 수 있는 것은 아닙다.
greetings = ["Hello", "Hallo", "Bonjour"];
names = ["Adrian Hill", "Klaus-Robert Müller"];
3×2 Matrix{String}:
"Hello Adrian Hill" "Hello Klaus-Robert Müller"
"Hallo Adrian Hill" "Hallo Klaus-Robert Müller"
"Bonjour Adrian Hill" "Bonjour Klaus-Robert Müller"
["$g $n" for g in greetings, n in names]
인덱싱과 뷰는 벡터와 동일하게 작동합니다. 수학 표기법과 마찬가지로 첫 번째 인덱스는 행을, 두 번째 인덱스는 열을 참조합니다.
A3 = 4×5 reshape(::UnitRange{Int64}, 4, 5) with eltype Int64:
1 5 9 13 17
2 6 10 14 18
3 7 11 15 19
4 8 12 16 20
A3 = reshape(1:20, 4, 5)
7
A3[3, 2]
열부터 읽어야한다. 메모리 생각한다면, 행부터 읽으면 매우 느리다.
3×3 Matrix{Int64}:
5 9 13
6 10 14
7 11 15
A3[begin:3, 2:end-1] # begin and end also work
3×3 view(reshape(::UnitRange{Int64}, 4, 5), 1:3, 2:4) with eltype Int64:
5 9 13
6 10 14
7 11 15
@view A3[begin:3, 2:end-1]
열 :기호는 다음을 위한 약어로 사용될 수 있습니다.begin:end
[2,6,10,14,18]
A3[2, :] # second row, all columns
행렬은 스칼라 값으로도 인덱싱할 수 있습니다. 이렇게 하면 배열의 열부터 시작하여 반복됩니다.
6
A3[6] # since we reshaped a range, A3[i] == i
숫자 알고리즘에서 꽤 자주 사용되는 배열을 초기화하는 특수한 방법도 있습니다.
이는 종종 구문을 따르며 function_name(Type, dims...), 여기서 Type및 는 dims둘 다 선택 사항입니다.
--0과 1
0으로 채워진 행렬을 얻으려면 다음을 사용합니다 zeros.
[0.0, 0.0, 0.0, 0.0, 0.0]
zeros(5) # vector
3×3 Matrix{Float64}:
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
zeros(3, 3) # matrix
3×5×2 Array{Int64, 3}:
[:, :, 1] =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
[:, :, 2] =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
zeros(Int, 3, 5, 2) # 3-dim array of type Int
이 함수는 ones와 정확히 같은 방식으로 작동 zeros하지만 1의 행렬을 생성합니다.
3×3 Matrix{Float32}:
1.0 1.0 1.0
1.0 1.0 1.0
1.0 1.0 1.0
ones(Float32, 3, 3) # matrix of type Float32
팁
LinearAlgebra.jl 섹션에서 단위 행렬에 대해 알아보겠습니다!
--사전 할당 행렬 ⁽⁺⁾
0과 1을 쓰는 데 시간이 걸릴 수 있습니다. 때로는 결과를 쓸 메모리 공간을 확보해야 할 때가 있습니다. 이를 사전 할당 이라고 합니다 .
처음부터 행렬을 생성하려면 다음을 사용하여 배열 생성자를 호출합니다 undef.out1
3×3 Matrix{Float32}:
-2.26882f-17 4.5872f-41 -2.26887f-17
4.5872f-41 -2.26885f-17 4.5872f-41
-2.26883f-17 4.5872f-41 -1.23491f-24
out1 = Array{Float32}(undef, 3, 3)
같은 모양의 행렬을 다른 행렬로 할당하고 싶다면 다음과 같이 하면 similar매우 편리합니다.out2
3×3 Matrix{Float32}:
7.17f-43 4.5872f-41 -2.79709f-24
0.0 -4.80552f-22 4.5872f-41
-4.80539f-22 4.5872f-41 -2.68841f-17
out2 = similar(out1) # similar type and shapeout3
3×3 Matrix{Int64}:
140598489012192 140598489012336 140598489012528
140598489012240 140598489012384 140598489012576
140598489012288 140598489012480 140598372818608
out3 = similar(out1, Int) # similar shape, but different typeout4
4×5 Matrix{Float32}:
-8.17644f-19 -8.17673f-19 -8.17574f-19 4.4302f-41 1.0f-45
4.5872f-41 4.5872f-41 4.5872f-41 0.0 0.0
-1.79363f-17 -6.53017f-18 -1.94289f-16 NaN 9.1834f-41
4.5872f-41 4.5872f-41 4.5872f-41 NaN 0.0
out4 = similar(out1, 4, 5) # similar type, but different shape
표준 Array유형만 사용할 수 있는 것은 아닙니다. Julia 표준 라이브러리는 희소 배열도 제공하며, 여러 패키지에서 자체 배열 유형을 구현합니다.
--SparseArrays.jl
희소 배열은 대부분 0으로 구성된 배열로, 특수한 데이터 구조와 매칭 알고리즘을 도입하는 것이 더 빠르고 메모리 효율적입니다.
using SparseArraysSA
3×8 SparseMatrixCSC{Int64, Int64} with 4 stored entries:
⋅ 2 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
⋅ ⋅ ⋅ 4 ⋅ 5 ⋅ ⋅
⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 3
SA = sparse([1, 3, 2, 2], [2, 8, 4, 6], [2, 3, 4, 5]) # rows, columns, values
입력을 표로 생각하면 도움이 될 수 있습니다.

// sparse로 컨버팅

--오프셋어레이.jl
Julia를 정말 좋아하시는데, 0부터 시작하는 인덱싱을 원하시나요? OffsetArrays.jl을 사용해 보세요 !
이 패키지를 사용하면 배열의 각 축에 임의의 시작 인덱스(양수, 0 또는 음수)를 정의할 수 있습니다. 0부터 시작하는 행렬을 정의해 보겠습니다.
using OffsetArrays
2×3 Matrix{Int64}:
1 2 3
4 5 6
A
OA = 2×3 OffsetArray(::Matrix{Int64}, 0:1, 0:2) with eltype Int64 with indices 0:1×0:2:
1 2 3
4 5 6
OA = OffsetArray(A, 0:1, 0:2) # row indices from 0 to 1, columns from 0 to 2
1
OA[0, 0]
우리는 0부터 시작하는 인덱싱을 고수할 필요는 없습니다. 원하는 인덱스를 사용할 수 있습니다.
OA2 = 2×3 OffsetArray(::Matrix{Int64}, -10:-9, 5:7) with eltype Int64 with indices -10:-9×5:7:
1 2 3
4 5 6
OA2 = OffsetArray(A, -10:-9, 5:7) # row indices from -10 to -9, columns from 5 to 7
5
OA2[-9, 6]
인덱싱과 뷰에 대해 배운 모든 내용은 OffsetArrays에도 적용됩니다.
view(OffsetArray(::Matrix{Int64}, 0:1, 0:2), 1, 1:2):
[5, 6]
@view OA[1, 1:end]
--StaticArrays.jl
때로는 정적 크기의 배열을 사용하여 작업할 수 있습니다. 예를 들어 회전 행렬을 설명하는 경우가 있습니다.
StaticArrays.jl 의 배열은 3x3 행렬의 역수를 계산하는 경우에서 볼 수 있듯이 엄청난 성능상의 이점을 제공할 수 있습니다.
using StaticArrays
M = 3×3 Matrix{Int64}:
1 2 3
4 6 5
7 8 9
M = [1 2 3; 4 6 5; 7 8 9] # regular matrix
정적 배열은 해당 유형에서 크기에 대한 추가 정보를 사용합니다.
SM = 3×3 SMatrix{3, 3, Int64, 9} with indices SOneTo(3)×SOneTo(3):
1 2 3
4 6 5
7 8 9
SM = SMatrix{3,3}(M) # matrix type from StaticArrays.jl
BenchmarkTools.jl@benchmark 의 매크로를 사용하여 함수를 벤치마킹할 수 있습니다 . 이 매크로는 각 함수를 여러 번 실행하여 통계와 실행 시간 히스토그램을 보여줍니다.
using BenchmarkTools
BenchmarkTools.Trial: 10000 samples with 193 evaluations per sample.
Range (min … max): 514.694 ns … 11.548 μs ┊ GC (min … max): 0.00% … 89.07%
Time (median): 524.767 ns ┊ GC (median): 0.00%
Time (mean ± σ): 553.249 ns ± 198.611 ns ┊ GC (mean ± σ): 2.05% ± 5.98%
█▄ ▁▄▂ ▁ ▁
███████▆▇██▅▅▄▄▄▁▁▁▁▁▃▃▁▄▁▁▁▁▁▃▁▁▁▁▁▁▃▄▃▄▁▁▁▁▁▁▁▃▁▁▁▁▁▁▄▆▇▆▄▅ █
515 ns Histogram: log(frequency) by time 1.39 μs <
Memory estimate: 1.86 KiB, allocs estimate: 4.
@benchmark inv(M)
BenchmarkTools.Trial: 10000 samples with 994 evaluations per sample.
Range (min … max): 30.833 ns … 1.669 μs ┊ GC (min … max): 0.00% … 95.92%
Time (median): 31.850 ns ┊ GC (median): 0.00%
Time (mean ± σ): 35.708 ns ± 57.375 ns ┊ GC (mean ± σ): 6.50% ± 3.97%
▅█▆▂ ▁▁ ▁
████████▇█▇█▇▆▇▇████▇▆▇▇▇▆▆▅▄▆▅▅▅▅▄▃▄▄▃▅▄▅▅▁▃▃▄▃▁▁▆▇▆▆▇▆█▇▇ █
30.8 ns Histogram: log(frequency) by time 66.9 ns <
Memory estimate: 80 bytes, allocs estimate: 1.
@benchmark inv(SM)
배열 반복
각 행을 출력하는 함수의 잘못된 구현을 먼저 보여줌으로써 배열 반복에 대한 동기를 부여해 보겠습니다.
나쁜 예: 이런건 하지말아야한다. 로우가 꼭 존재하는것은 아님, 예를들면, 오프셋어레이
iterate_over_rows_bad (generic function with 1 method)
function iterate_over_rows_bad(A::AbstractMatrix)
n_rows = size(A, 1)
for i in 1:n_rows
@info A[i, :]
end
end
2×3 Matrix{Int64}:
1 2 3
4 5 6
A
iterate_over_rows_bad(A) # works!

우리 함수는 행렬에서 작동합니다 . 하지만 함수의 A인수 유형 선언 에서는 모든 행렬 유형에서 작동한다고 명시되어 있습니다!::AbstractMatrix
이전에 정의한 OffsetArray를 전달하면 어떤 일이 일어나는지 살펴보겠습니다.
2×3 OffsetArray(::Matrix{Int64}, 0:1, 0:2) with eltype Int64 with indices 0:1×0:2:
1 2 3
4 5 6
OA
Error messageBoundsError: 인덱스 0:1×0:2, eltype Int64를 사용하여 2×3 OffsetArray(::Matrix{Int64}, 0:1, 0:2)에 액세스하려고 시도했습니다. 인덱스는 [2, OffsetArrays.IdOffsetRange(values=0:2, indices=0:2)]입니다.Stack trace
Here is what happened, the most recent locations are first:
1. throw_boundserror(A::OffsetArrays.OffsetMatrix{…}, I::Tuple{…}) ...show types...from julia → abstractarray.jl:737
2. checkboundsfrom abstractarray.jl:702
3. _getindexfrom multidimensional.jl:888
4. getindexfrom abstractarray.jl:1290
5. macro expansionfrom logging.jl:374
6. iterate_over_rows_bad(A::OffsetArrays.OffsetMatrix{…}) ...show types...from Other cell: line 4
n_rows = size(A, 1) for i in 1:n_rows @info A[i, :] endend
7. Show more...1iterate_over_rows_bad(OA)OffsetArray(::Vector{Int64}, 0:2):
4
5
6
범위를 벗어난 오류가 발생합니다!
nrows여전히 2이므로 for-loop의 print 문은 .을 인쇄하려고 시도합니다 OA[2, :].
더욱 강력한 구현에서는 반복자를 사용합니다 eachrow.
iterate_over_rows_good (generic function with 1 method)
function iterate_over_rows_good(A::AbstractMatrix)
for row in eachrow(A)
@info row
end
end
iterate_over_rows_good(A) # works and automatically uses views!

iterate_over_rows_good(OA) # also works and uses views!

팁
배열을 반복할 때는 가능한 한 다음 반복자를 사용하는 것이 좋습니다.
• eachrow- 행을 반복합니다
• eachcol- 열 반복
• eachslice- nd-array의 모든 슬라이스에 대한 반복자
• eachindex- 배열의 모든 인덱스를 반복합니다.
LinearAlgebra.jl 패키지는 Julia 표준 라이브러리의 일부이지만 명시적으로 로드해야 합니다.
using LinearAlgebra
LinearAlgebra.jl은 선형 대수 패키지에서 기대하는 모든 함수를 제공합니다.
3×3 Matrix{Int64}:
1 2 3
4 6 5
7 8 9
M
-18.0
det(M) # determinant
16
tr(M) # trace
3×3 Matrix{Float64}:
-0.777778 -0.333333 0.444444
0.0555556 0.666667 -0.388889
0.555556 -0.333333 0.111111
inv(M) # matrix inverse
3.7416573867739413
norm([1, 2, 3]) # ℓ2-norm
6.0
norm([1, 2, 3], 1) # ℓ1-norm
행렬 곱셈
Julia에서는 표준 *-연산자를 사용하여 행렬을 곱합니다. 간단한 배열을 곱해 보겠습니다.
3×3 Matrix{Int64}:
1 2 3
4 6 5
7 8 9
M
u = [1, 2, 3]
u = [1, 2, 3]
v = [4, 3, 2]
v = [4, 3, 2]
두 개의 배열을 곱할 때그리고, Julia는 치수를 예상합니다.그리고일치하지 않으면 DimensionMismatch오류가 발생합니다.
16, 44, 70
M * v # works
Error message from LinearAlgebraDimensionMismatch: 행렬 A의 차원은 (3,1)이고, 행렬 B의 차원은 (3,3)입니다.Show stack trace...
u * M # Error: u has dimensions (3, 1), but M has dimensions (3, 3)
Julia의 벡터는 크기가 nx1인 열 벡터입니다.. 우리는 그것들을 1xn으로 재구성할 수 있습니다행 벡터를 사용하여 transpose:
1×3 transpose(::Vector{Int64}) with eltype Int64:
1 2 3
transpose(u)
u실수 값이므로, 수반 연산자' ( 켤레 전치 연산자 라고도 함 )를 사용할 수도 있습니다. (adjoint or conjugate transpose)
1×3 adjoint(::Vector{Int64}) with eltype Int64:
1 2 3
u'
이제 모양이 일치하므로 배열을 곱할 수 있습니다.
1×3 adjoint(::Vector{Int64}) with eltype Int64:
30 38 40
u' * M # (1, 3) × (3, 3) → (1, 3)
314
u' * M * v
고차 텐서에 대한 행렬 곱셈은 정의되지 않았습니다.
점곱
두 벡터의 내적을 계산해 보겠습니다 .
이전 슬라이드에서 배웠듯이, u * v행렬 곱셈을 구현하고 차원이 일치하지 않기 때문에 오류가 발생 u합니다 v.
그러나 우리는 먼저 를 전치하여 점곱을 구현할 수 있습니다 u.,
16
transpose(u) * v
16
u' * v
dotLinearAlgebra는 또한 연산자 ⋅( )를 통해 사용할 수 있는 함수를 제공합니다 \cdot<TAB>.
16
dot(u, v)
16
u ⋅ v
단위 행렬
Julia에서는 단위 행렬을 할당할 필요가 없습니다. LinearAlgebra는 I모든 크기의 단위 행렬을 다음과 같이 표현합니다.
UniformScaling{Bool}
true*I
I # Indentity matrix is of type `UniformScaling`
단위 행렬은 모든 행렬의 곱셈 단위 역할을 합니다.

2×3 Matrix{Int64}:
1 2 3
4 5 6
A
2×3 Matrix{Int64}:
1 2 3
4 5 6
I * A
2×3 Matrix{Int64}:
1 2 3
4 5 6
A * I
Julia 표준 라이브러리는 난수를 추출하는 여러 함수를 제공합니다. 그중 두 가지를 살펴보겠습니다.
• rand: 균일 분포의 샘플
• randn: 정규 분포의 샘플
0.980601388632647
rand()
-0.07185332535057928
randn()
값 의 벡터를 그려 50k히스토그램으로 시각화하여 모든 것이 예상대로 작동하는지 확인해 보겠습니다.
using UnicodePlots
┌ ┐
[0.0, 0.1) ┤███████████████████████████████▏ 4 839
[0.1, 0.2) ┤███████████████████████████████▌ 4 896
[0.2, 0.3) ┤████████████████████████████████▏ 4 994
[0.3, 0.4) ┤███████████████████████████████▉ 4 981
[0.4, 0.5) ┤████████████████████████████████▏ 4 989
[0.5, 0.6) ┤████████████████████████████████▌ 5 076
[0.6, 0.7) ┤████████████████████████████████▍ 5 043
[0.7, 0.8) ┤███████████████████████████████▉ 4 985
[0.8, 0.9) ┤█████████████████████████████████ 5 142
[0.9, 1.0) ┤████████████████████████████████▌ 5 055
└ ┘
Frequency
rand(50000) |> histogram
┌ ┐
[-5.0, -4.5) ┤▏ 1
[-4.5, -4.0) ┤▏ 3
[-4.0, -3.5) ┤▏ 14
[-3.5, -3.0) ┤▎ 57
[-3.0, -2.5) ┤▊ 247
[-2.5, -2.0) ┤██▋ 796
[-2.0, -1.5) ┤███████▌ 2 177
[-1.5, -1.0) ┤███████████████▋ 4 592
[-1.0, -0.5) ┤█████████████████████████▋ 7 490
[-0.5, 0.0) ┤█████████████████████████████████ 9 651
[ 0.0, 0.5) ┤████████████████████████████████▌ 9 516
[ 0.5, 1.0) ┤█████████████████████████▋ 7 522
[ 1.0, 1.5) ┤███████████████▋ 4 595
[ 1.5, 2.0) ┤███████▋ 2 239
[ 2.0, 2.5) ┤██▋ 787
[ 2.5, 3.0) ┤▊ 247
[ 3.0, 3.5) ┤▎ 62
[ 3.5, 4.0) ┤▏ 4
└ ┘
Frequency
randn(50000) |> histogram
우리는 임의의 모양으로 난수 배열을 그릴 수 있습니다
2×3×2 Array{Float64, 3}:
[:, :, 1] =
0.471374 0.20006 0.775217
0.284587 0.880843 0.946142
[:, :, 2] =
0.93366 0.43835 0.548389
0.626947 0.709209 0.793199
rand(2, 3, 2)
원하는 출력 유형도 지정합니다.
2×3×2 Array{Float32, 3}:
[:, :, 1] =
0.6562 0.886861 0.282816
0.495501 0.509896 0.31315
[:, :, 2] =
0.807384 0.810474 0.838697
0.11348 0.583264 0.921531
rand(Float32, 2, 3, 2)
팁
rand 또한 randn 난수 생성기를 전달하여 결정적으로 사용할 수도 있습니다.
julia> using Random
julia> rng = MersenneTwister(1234); # use seed 1234
julia> randn(rng, Float32)
0.8673472f0
Iterables에서 샘플링
범위, 벡터, 문자열, 튜플 등 반복 가능한 모든 항목에서 샘플링할 수도 있습니다.
4×4 Matrix{Int64}:
2 3 4 2
4 1 3 4
3 1 2 2
3 2 3 1
rand(1:4, 4, 4)
4×4 Matrix{Int64}:
5 9 9 5
9 5 9 9
9 5 9 5
5 9 5 9
rand((5, 9), 4, 4)
4×4 Matrix{Char}:
'c' 'b' 'a' 'c'
'c' 'b' 'c' 'c'
'c' 'a' 'a' 'b'
'c' 'c' 'b' 'a'
rand("abc", 4, 4)
week_meal_plan = 3×7 Matrix{String}:
"Soup" "Soup" "Pizza" "Soup" "Salad" "Salad" "Salad"
"Salad" "Pizza" "Soup" "Soup" "Pizza" "Soup" "Salad"
"Pizza" "Salad" "Salad" "Salad" "Pizza" "Soup" "Salad"
week_meal_plan = rand(["Pizza", "Salad", "Soup"], 3, 7)
분포에서의 샘플링
Distributions.jl 패키지를 사용하면 더 복잡한 분포를 정의하고 이를 샘플링할 수 있습니다.
using Distributions
┌ ┐
[-12.0, -10.0) ┤▏ 2
[-10.0, -8.0) ┤▏ 7
[ -8.0, -6.0) ┤▏ 42
[ -6.0, -4.0) ┤▌ 368
[ -4.0, -2.0) ┤████▎ 2 866
[ -2.0, 0.0) ┤███████████████████████████████▉ 21 682
[ 0.0, 2.0) ┤████████████████████████████████ 21 698
[ 2.0, 4.0) ┤████▍ 2 888
[ 4.0, 6.0) ┤▌ 391
[ 6.0, 8.0) ┤▏ 50
[ 8.0, 10.0) ┤▏ 5
[ 10.0, 12.0) ┤▏ 1
└ ┘
Frequency
begin
μ = 0
θ = 1
distribution = Laplace(μ, θ)
rand(distribution, 50000) |> histogram
end
줄리아에서
rng = MersenneTwister(1234)
의 뜻은 **“시드값이 1234인 메르센 트위스터(Mersenne Twister) 난수 생성기(rng) 객체를 만든다”**입니다.
여기서 rng는 Random Number Generator의 약어로, “난수 생성기”를 뜻합니다.
즉 이 코드는
MersenneTwister(1234): “1234”라는 시드값(seed value)으로 초기화된 메르센 트위스터 방식의 난수 생성기를 생성함
이를 변수 rng에 저장함
이후에 rng를 사용해 난수(random numbers)를 생성할 때마다 항상 동일한 시드로 동일한 시퀀스의 난수를 얻을 수 있습니다.
이것은 실험의 재현성, 결과 일관성을 위하여 중요합니다.
정리:
rng = MersenneTwister(1234) : “1234”로 초기화한 난수 생성기를 만든다
rng : “Random Number Generator(난수 생성기)”의 약어
Random.seed!와의 차이점은?
차이점은 다음과 같습니다:
- Random.seed!(1234)
글로벌(전역) 난수 생성기를 시드 1234로 초기화합니다.
즉, 이후 rand() 같은 기본 랜덤 함수들이 모두 같은 시퀀스를 만듭니다.
별도의 난수 생성기 객체를 만들지 않고, 전체 프로그램에서 전역적으로 시드가 적용됩니다.
- rng = MersenneTwister(1234)별도의 난수 생성기(rng) 객체를 시드 1234로 만듭니다.
필요할 때마다 이 rng를 직접 넘겨서 사용합니다. 예시: rand(rng, 1:10)
글로벌 난수 생성기와 별도로 독립적이기 때문에, 여러 난수 시퀀스를 동시에 관리하거나, 특정 부분에서만 다른 시드를 사용할 때 좋습니다.
정리:
- Random.seed!는 전역(Global) RNG에만 적용
- MersenneTwister(1234)는 독립적인 RNG 객체 생성여러 난수 스트림, 병렬 작업, 재현성을 세밀하게 관리하고 싶을 때는 MersenneTwister 객체 사용을 추천
이전 강의에서 벡터에 대한 브로드캐스팅을 이미 살펴보았습니다. 고차원 배열의 경우 동작은 좀 더 복잡합니다.
브로드캐스트는 추가 메모리를 사용하지 않고 다른 배열의 해당 차원과 일치하도록 배열 인수의 싱글톤 차원을 확장하고 주어진 함수를 요소별로 적용합니다.
예를 들어 추가 방송을 살펴보겠습니다.

줄리아는 확장할 것이다 P그리고 Q에게

추가 메모리를 할당하지 않고 다음을 추가합니다.

이로 인해.

P = rand(2, 3, 1, 1, 1);
Q = rand(1, 1, 4, 5);
R = P .+ Q;

P의 3번째 요소가 1,4일때만 동작, 2,3,5일때는 동작하지 않음
코드에서
julia
P = rand(2, 3, 1, 1, 1)
Q = rand(1, 1, 4, 5)
R = P .+ Q
여기서 P와 Q를 브로드캐스팅해서 합칠 때, 브로드캐스팅(자동 차원 맞춤) 규칙 때문에 “3번째 1”이 1이거나 4일 때만 동작하고, 2, 3, 5일 때는 에러가 나는 겁니다.
이유 설명:
- 줄리아에서 브로드캐스팅(.+, .* 등)은 같은 위치의 차원이 다르면,
-- 한쪽이 1이면 자동으로 늘려서 맞춰줌(=broadcasting)
-- 두쪽 모두 1이 아니고 숫자가 다르면 에러.
여기서
- P의 shape: (2, 3, 1, 1, 1)
- Q의 shape: (1, 1, 4, 5)
- 브로드캐스팅 대상 shape은 (2, 3, 4, 5, 1)로 자동 확장됨
즉,
- 3번째 차원이 P는 1, Q는 4여서 맞춤이 가능
- 만약 P가 (2,3,2,1,1) 등으로 “3번째 차원”에 1 대신 2, 3, 5 등을 주면
-- Q는 4로, P도 2/3/5로, 한쪽이 1이 아니므로 늘릴 수 없는 상황
-- → 브로드캐스팅 규칙 위반으로 에러 발생
핵심:
- 두 배열 shape에서 각 차원이 [[한쪽이라도 1이거나, 또는 둘 다 같은 숫자]]면 브로드캐스팅 가능
- 둘 다 1이 아니고 숫자가 다르면 "DimensionMismatch" 에러

size(P)
size(Q)
size(R)
이 강의에서는 고차원 배열에서 알고리즘을 구현하는 데 유용한 도구인 데카르트 인덱스에 대해 다루지 못했습니다. 다음 블로그 게시물에서 데카르트 인덱스에 대한 훌륭한 소개를 확인할 수 있습니다.
• Tim Holy의 [다차원 알고리즘 및 반복](https://julialang.org/blog/2016/02/iteration/)
• [데카르트 지수에 대한 Julia 문서](https://docs.julialang.org/en/v1/manual/arrays/#Cartesian-indices)
Julia 생태계는 SparseArrays.jl* , *OffsetArrays.jl* , *StaticArrays.jl* 외에도 다양한 패키지를 제공합니다.
• [JuliaArrays](https://github.com/JuliaArrays): 사용자 정의 배열 유형을 구현하는 패키지를 유지 관리하는 GitHub의 조직
• [JuliaLinearAlgebra](https://github.com/JuliaLinearAlgebra): 선형 대수 방법과 행렬 유형을 구현하는 패키지를 유지 관리하는 GitHub의 조직
• [Tullio.jl](https://github.com/mcabbott/Tullio.jl): GPU에서도 작동하는 einsum 매크로
- 수평 연결( *열 방향* ): 공백, 탭 및 이중 세미콜론`;;`
- 수직 연결( *행 방향* ): 줄 바꿈 및 세미콜론`;`
1. 1. [...show types...](https://juml-tub.github.io/julia-ml-course/lectures/L2_Basics_2.html#)
**throw_boundserror**(A::OffsetArrays.OffsetMatrix{…}, I::Tuple{…})
from [**julia** → *abstractarray.jl:737*](https://github.com/JuliaLang/julia/tree/95f30e51f4158dd3421cd5b8098849d24e97e497/base/abstractarray.jl#L737)
2. 2. **checkbounds** from *abstractarray.jl:702*
3. 3. **_getindex** from *multidimensional.jl:888*
4. 4. **getindex** from *abstractarray.jl:1290*
5. 5. **macro expansion** from *logging.jl:374*
6. 6. [...show types...](https://juml-tub.github.io/julia-ml-course/lectures/L2_Basics_2.html#) [`n_rows = size(A, 1) for i in 1:n_rows **@info** A[i, :] endend`](https://juml-tub.github.io/julia-ml-course/lectures/L2_Basics_2.html#867c276d-4c43-4465-bc9b-621b97c0d2b8)
**iterate_over_rows_bad**(A::OffsetArrays.OffsetMatrix{…}) from [Other cell: *line 4*](https://juml-tub.github.io/julia-ml-course/lectures/L2_Basics_2.html#867c276d-4c43-4465-bc9b-621b97c0d2b8)
7. 7. [Show more...](https://juml-tub.github.io/julia-ml-course/lectures/L2_Basics_2.html#)
- `eachrow`- 행을 반복합니다
- eachcol`- 열 반복
- `eachslice`- nd-array의 모든 슬라이스에 대한 반복자
- `eachindex`- 배열의 모든 인덱스를 반복합니다.
- `rand`: 균일 분포의 샘플
- `randn`: 정규 분포의 샘플
- Tim Holy의 [다차원 알고리즘 및 반복](https://julialang.org/blog/2016/02/iteration/)
- [데카르트 지수에 대한 Julia 문서](https://docs.julialang.org/en/v1/manual/arrays/#Cartesian-indices)
- [JuliaArrays](https://github.com/JuliaArrays): 사용자 정의 배열 유형을 구현하는 패키지를 유지 관리하는 GitHub의 조직
- [JuliaLinearAlgebra](https://github.com/JuliaLinearAlgebra): 선형 대수 방법과 행렬 유형을 구현하는 패키지를 유지 관리하는 GitHub의 조직
- [Tullio.jl](https://github.com/mcabbott/Tullio.jl): GPU에서도 작동하는 einsum 매크로
출처:
https://juml-tub.github.io/julia-ml-course/L2_Basics_2/
https://juliakorea.github.io/ko
이전 강의
[AI 인공지능 머신러닝 딥러닝/Julia] - Julia 프로그래밍 - 유형, 제어 흐름, 함수 및 다중 디스패치
Julia 프로그래밍 - 유형, 제어 흐름, 함수 및 다중 디스패치
[AI 인공지능 머신러닝 딥러닝/Julia] - Julia 프로그래밍 - 언어 및 강의 소개 Julia 프로그래밍 - 언어 및 강의 소개Julia 프로그래밍 언어줄리아(Julia)는 고성능의 수치 해석 및 계산과학의 필요 사항
inner-game.tistory.com
다음 강의
[AI 인공지능 머신러닝 딥러닝/Julia] - Julia 프로그래밍 - 플롯과 데이터 프레임
Julia 프로그래밍 - 플롯과 데이터 프레임
[AI 인공지능 머신러닝 딥러닝/Julia] - Julia 프로그래밍 - 언어 및 강의 소개 Julia 프로그래밍 - 언어 및 강의 소개Julia 프로그래밍 언어줄리아(Julia)는 고성능의 수치 해석 및 계산과학의 필요 사항
inner-game.tistory.com