Slicing and Indexing (3주차)

post-thumbnail

1D Tensor 절단하기

x = torch.arange(10)

print('x[0]=', x[0])
print('x[-1]=', x[-1])
print('x[2:5]=', x[2:5])
print('x[:5]=', x[:5])
print('x[5:]=', x[5:])
print('x[::2]=', x[::2])
print('x[[1,2,5]]=', x[[1,2,5]])

x[0]= tensor(0)
x[-1]= tensor(9)
x[2:5]= tensor([2, 3, 4])
x[:5]= tensor([0, 1, 2, 3, 4])
x[5:]= tensor([5, 6, 7, 8, 9])
x[::2]= tensor([0, 2, 4, 6, 8])
x[[1,2,5]]= tensor([1, 2, 5])

  1. Numpy와 같이 텐서는 index를 통한 텐서의 절단이 가능하다.
  2. x[0]은 첫 항목이고, x[-1]은 마지막 항목을 의미한다.
  3. x[2:5] 처럼 시작(start)와 끝(end)을 이용한 절단도 가능하고, 이 때, start와 end는 음수를 사용해도 된다.
  4. 단, x[::2]에서와 같이 보폭(step)을 지정하는 경우에서, step은 양수만 가능하다.

1D Tensor 값 변경하기

x[0] = 10
print('x=', x)
x[2:5] = torch.tensor([20, 30, 40])
print('x=', x)

x= tensor([10, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x= tensor([10, 1, 20, 30, 40, 5, 6, 7, 8, 9])

  1. Numpy와 같이 텐서는 index를 통해 변수의 값을 변경할 수 있다.
  2. x[0]처럼, 한 개만 교체할 수도 있지만, x[2:5]처럼 start와 end사이의 index에 torch.tensor()를 통해, 여러개의 값을 한꺼번에 교체할 수도 있다.

2D Tensor 절단하기

x = torch.arange(9).reshape((3, 3))
print('x=', x)

x= tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])

print('x[0,0]=', x[0,0])
print('x[0,:]=', x[0,:])
print('x[:,0]=', x[:,0])
print('x[:,[0,2]]=', x[:,[0,2]])

x[0,0]= tensor(0)
x[0,:]= tensor([0, 1, 2])
x[:,0]= tensor([0, 3, 6])
x[:,[0,2]]= tensor([[0, 2],
[3, 5],
[6, 8]])

  1. 1D 텐서와 같이 이차원 텐서에서도 인덱싱과 절단이 가능하다.
  2. x는 torch.Size([3, 3])인 텐서이고, x[0, 0]은 0행 0열의 값을 지정한다.
  3. x[0, :]은 0행 전체, x[:, 0]은 0열 전체를 절단한다.
  4. x[:, [0, 2]] 는 0열과 2열의 전체를 함께 절단한다.

Tensor 절단하기

print('x[0:2, 0:2]=', x[0:2, 0:2])
print('x[..., 0]=', x[..., 0])

x[0:2, 0:2]= tensor([[0, 1],
[3, 4]])
x[..., 0]= tensor([0, 3, 6])

  1. x[0:2, 0:2] 처럼, 행과 열을 모두 start:end를 이용해 절단할 수도 있다.
  2. x[..., 0]는 0열만을 절단한 tensor([0, 3, 6])과 같다.

3D Tensor 절단하기

y = torch.arange(9).reshape((1, 3, 3))
print('y=', y)
print('y[0, 0, 0]=', y[0, 0, 0])
print('y[:, :, 0]
  1. 1D 텐서와 같이 3차원 텐서에서도 indexing과 slicing이 가능하다.
  2. y는 torch.Size([1, 3, 3])인 3D 텐서이다.
  3. y[0, 0, 0] 처럼 깊이, 행, 옆에서 모두 0의 위치의 원소를 나타낸다.
  4. y[:, :, 0]와 y[..., 0]는 같은 결과를 0열의 원소를 절단하기 때문에 그 결과는 같다.

Index로 Tensor 교환

x = torch.arange(12).reshape(3, 4)
print('x=', x)

indices = torch.randperm(x.shape[0])
print('indices=', indices)

y = x[indices]
print('y=', y)

x= tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
indices= tensor([1, 0, 2])
y= tensor([[ 4, 5, 6, 7],
[ 0, 1, 2, 3],
[ 8, 9, 10, 11]])

Index로 Tensor 선택하기

x = torch.arange(1, 10)
print('x=', x)
indx = range(x.shape[0])[::-1]
indx = torch.IntTensor(indx)
print('indx=', indx)

x= tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
indx= tensor([8, 7, 6, 5, 4, 3, 2, 1, 0], dtype=torch.int32)

y = torch.index_select(x, 0, indx)
print('y=', y)

y= tensor([9, 8, 7, 6, 5, 4, 3, 2, 1])

  1. x는 1D 텐서이다.
  2. 1D 텐서인 x를 정수 index 텐서인 indx를 이용하여, x의 역순 텐서인 y를 생성한 것이다.
x = x.view(-1, 3)
print('x=', x)
indx = torch.IntTensor([0, 1])
y = x.index_select(0, indx)
print('y=', y)
z = x.index_select(1, indx)
print('z=', z)

x= tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
y= tensor([[1, 2, 3],
[4, 5, 6]])
z= tensor([[1, 2],
[4, 5],
[7, 8]])

  1. x는 2D 텐서이다.
  2. 2D 텐서인 x에서 indx에 명시된 차원인 0과 1을 선택한다.
  3. y는 torch.index_select(x, 0, indx)에서 x의 차원(dim)이 0행에서 indx에 명시된 0, 1행을 y에 저장한 것이다.
  4. z는 torch.index_select(x, 1, indx)에서 x의 차원(dim)이 1(열)에서 indx에 명시된 0, 1열을 y에 저장한 것이다.

Tensor의 스칼라 연산

torch.set_printoptions(precision=2)
x = torch.tensor([1,2])
print('x+1=', x+1)
print('x-1=', x-1)
print('x*2=', x*2)
print('x/2=', x/2)
print('x**2=', x**2)

x+1= tensor([2, 3])
x-1= tensor([0, 1])
x*2= tensor([2, 4])
x/2= tensor([0.50, 1.00])
x**2= tensor([1, 4])

set_printoptions는 소수점 몇째자리까지 출력하는지를 보여준다.
1. x는 1D텐서이고 1은 상수이다.
2. 상수와의 연산은 텐서의 각 element에 대해 해당 상수값을 각각 산술연산하여 텐서에 반환한다.

Tensor간의 연산

y = torch.tensor([3, 4])
print('x+y=', x+y)
print('x-y=', x-y)
print('x*y=', x*y)
print('x/y=', x/y)
print('x**y=', x**y)

x+y= tensor([4, 6])
x-y= tensor([-2, -2])
x*y= tensor([3, 8])
x/y= tensor([0.33, 0.50])
x**y= tensor([ 1, 16])

  1. x는 1D 텐서이고 y도 1D 텐서이다.
  2. x와 y는 모두 torch.Size([2])인 1차원 텐서이므로, 두 모양이 같다. 이런 경우, 산술 연산은 동일한 위치에 있는 텐서의 값들에 대해 산술 연산을 시행한다.
x = torch.tensor([[1,2],[3,4]])
y = torch.tensor([1,2])

print('shape of x:', x.shape)
print('shape of y:', y.shape)
print('x+y=', x+y)
print('x-y=', x-y)
print('x*y=', x*y)
print('x/y=', x/y)
print('x**y=', x**y)

shape of x: torch.Size([2, 2])
shape of y: torch.Size([2])
x+y= tensor([[2, 4],
[4, 6]])
x-y= tensor([[0, 0],
[2, 2]])
x*y= tensor([[1, 4],
[3, 8]])
x/y= tensor([[1., 1.],
[3., 2.]])
x**y= tensor([[ 1, 4],
[ 3, 16]])

x = torch.tensor([1,4,5,6])
y = torch.tensor([2,3,5,7])

print('x==1:', x==1)
print('x==y:', x==y)
print('x!=y:', x!=y)
print('x>1:', x>1)
print('x>y:', x>y)
print('x>=y:', x>=y)
print('x<y:', x<y)
print('x<=y:', x<=y)
print('~(x<=y):', ~(x<=y))

x==1: tensor([ True, False, False, False])
x==y: tensor([False, False, True, False])
x!=y: tensor([ True, True, False, True])
x>1: tensor([False, True, True, True])
x>y: tensor([False, True, False, False])
x>=y: tensor([False, True, True, False])
x<y: tensor([ True, False, False, True])
x<=y: tensor([ True, False, True, True])
~(x<=y): tensor([False, True, False, False])

  1. x는 2D 텐서이고, y도 1D 텐서이다.
  2. x와 y는 모두 행의 수가 2로 동일하다. 이러한 경우, y를 앞의 x의 torch.Size([2, 2])로 확장하여 각 요소별로 산술연산을 시행하게 된다.
  3. x와 y의 각 원소별로 비교연산을 수행할 수 있다.
  4. 동일한 위치의 원소끼리 ==, !=, >, <, >=, <= 등의 연산을 수행하여, 그 결과를 True와 False의 값으로 나타내준다.
  5. 'x==1'은 torch.eq(x, 1) 또는 x.eq(1)과 같다.

Boolean Indexing

  1. Boolean Indexing이란, 데이터 구조와 동일한 차원/길이를 가지는 Boolean Mask를 통해 결과가 True인 배열의 값만을 선택적으로 추출하거나 조작하는 데이터 기법이다.
  2. 단, Boolean mask의 크기는 데이터 구조와 정확히 일치해야 한다.
  3. 반복문 없이 조건 연산을 한번에 적용할 수 있어 계산이 빠르다.
z = torch.tensor([-1, 1, 2, -2, -3])
print('z>0=', z>0)
print('z[z>0]', z[z>0])
z[z<0] = 0
print('z=:', z)

z>0= tensor([False, True, True, False, False])
z[z>0] tensor([1, 2])
z=: tensor([0, 1, 2, 0, 0])

  1. z[z>0]은 z에서 z>0조건을 만족하는 텐서 tensor([1, 2])만 반환한다.
  2. z[z<0] = 0은 z텐서의 항목이 음수인 경우 값을 0으로 변경한 후, z를 반환한다.

Logical Operation

x = torch.tensor([True, True, False, False])
y = torch.tensor([True, False, True, False])
print('and(x, y):', torch.logical_and(x, y))
print('or(x, y):', torch.logical_or(x, y))
print('not(x):', torch.logical_not(x))

and(x, y): tensor([ True, False, False, False])
or(x, y): tensor([ True, True, True, False])
not(x): tensor([False, False, True, True])

  1. torch.logical_and(), torch.logical_or(), torch.logical_not()은 논리곱, 논리합, 논리부정을 계산한다.

Bit Operation

x = torch.tensor([True, True, False, False])
y = torch.tensor([True, False, True, False])

print('bit_and(x,y):', torch.bitwise_and(x,y))
print('bit_or(x,y):', torch.bitwise_or(x,y))
print('bit_not(x):', torch.bitwise_not(x))

bit_and(x,y): tensor([ True, False, False, False])
bit_or(x,y): tensor([ True, True, True, False])
bit_not(x): tensor([False, False, True, True])

  1. 비트연산을 통한 곱, 합과 부정을 나타내며, 그 결과는 논리연산과 같다.

정수 텐서에서의 Bit Operation

x = torch.tensor([1,2,3,-1], dtype=torch.int8)
y = torch.tensor([2,3,4,-2], dtype=torch.int8)

print('bit_and(x,y):', torch.bitwise_and(x,y))
print('bit_or(x,y):', torch.bitwise_or(x,y))
print('bit_not(x):', torch.bitwise_not(x))

print('x<<2:', torch.bitwise_left_shift(x,2))
print('x>>2:', torch.bitwise_right_shift(x,2))

bit_and(x,y): tensor([ 0, 2, 0, -2], dtype=torch.int8)
bit_or(x,y): tensor([ 3, 3, 7, -1], dtype=torch.int8)
bit_not(x): tensor([-2, -3, -4, 0], dtype=torch.int8)
x<<2: tensor([ 4, 8, 12, -4], dtype=torch.int8)
x>>2: tensor([ 0, 0, 0, -1], dtype=torch.int8)

  1. 정수 텐서에서도 비트를 이용한 곱, 합, 부정과 shift의 계산을 할 수 있다.

0개의 댓글