PyTorch의 Tensor 연산 퀵 레퍼런스

이 글은 PyTorch를 이용한 딥러닝 개발 시에 Tensor 연산에 대한 내용을 빠르게 참조하기 위해 정리한 글입니다.

#1. 난수값으로 구성된 2×3 텐서 생성

import torch

x = torch.rand(2,3)
print(x)

#2. 정규분포 난수값으로 구성된 2×3 텐서 생성

import torch

x = torch.randn(2,3)
print(x)

#3. [0,10) 까지의 정수형 난수값으로 구성된 2×3 텐서 생성

import torch

x = torch.randint(0,10,size=(2,3))
print(x)

#4. 0으로 채워진 2×3 텐서 생성

import torch

x = torch.zeros(2,3)
print(x)

#5. 다른 텐서의 형상과 동일한 Zero 텐서 생성하기

import torch

ref = torch.rand(2,3)
x = torch.zeros_like(ref)
print(x)

#6. 1로 채워진 2×3 텐서 생성하기

import torch

x = torch.ones(2,3)
print(x)

#7. 다른 텐서의 형상과 동일한 1값으로 구성된 텐서 생성하기

import torch

ref = torch.rand(2,3)
x = torch.ones_like(ref)
print(x)

#8. 텐서의 타입 얻기

import torch

x = torch.rand(2,3)
print(x.type()) # torch.FloatTensor
print(type(x)) # 

#9. 요소값을 정수형 값으로 변환한 텐서 생성하기

import torch

x = torch.rand(2,3) + 1.5
int_x = x.type(dtype=torch.IntTensor)
print(int_x)

#10. 넘파이 배열로부터 텐서 만들기, 텐서로부터 넘파이 배열 만들기

import torch
import numpy as np

x1 = np.ndarray(shape=(2,3), dtype=int, buffer=np.array([1,2,3,4,5,6]))
x2 = torch.from_numpy(x1)
print(x2, x2.type())

x3 = x2.numpy()
print(x3)

#11. 요소값 배열을 통해 실수형 텐서 만들기

import torch

x = torch.FloatTensor([[1,2,3],[4,5,6]])
print(x)

#12. 텐서를 GPU에, 또는 CPU로 옮기기

import torch

x = torch.FloatTensor([[1,2,3],[4,5,6]])

cpu = torch.device('cpu')
gpu = torch.device('cuda')

if torch.cuda.is_available():
    x_gpu = x.to(gpu)
    print(x_gpu)

x_cpu = x_gpu.to(cpu)
print(x_cpu)

#13. 텐서의 크기

import torch

x = torch.FloatTensor(2,3,4,4)
print(x.size()) # torch.Size([2, 3, 4, 4])
print(x.size()[1:2]) torch.Size([3])

#14. 텐서의 요소값 접근

import torch

x = torch.randn(4,3)
print(x)
''' output:
tensor([[ 0.1477,  0.4707, -0.7333],
        [ 0.8718,  0.1213,  0.6299],
        [ 0.2991,  1.1437, -0.7631],
        [ 1.3319,  0.8322, -2.4153]])
'''

print(x[1:3,:])
''' output:
tensor([[ 0.8718,  0.1213,  0.6299],
        [ 0.2991,  1.1437, -0.7631]])
'''

#15. 인덱스값으로 지정된 요소값으로 구성된 새로운 텐서 생성하기(값 복사됨)

import torch

x = torch.randn(4,3)
print(x)
'''output:
tensor([[-0.1728,  0.0887, -0.0186],
        [ 0.9492, -0.0452,  0.5660],
        [-0.4184, -0.2162,  1.0297],
        [-0.5110,  0.2452,  1.0734]])
'''

selected = torch.index_select(x,dim=1,index=torch.LongTensor([0,2]))
print(selected)
'''output:
tensor([[-0.1728, -0.0186],
        [ 0.9492,  0.5660],
        [-0.4184,  1.0297],
        [-0.5110,  1.0734]])
'''

#16. 마스크 텐서로 새로운 텐서 생성하기

import torch

x = torch.randn(2,3)
print(x)
'''output:
tensor([[ 0.1622,  1.1205, -0.4761],
        [ 0.9225,  0.2151,  0.2192]])
'''

mask = torch.BoolTensor([[False, False, True],[False,True,False]])
out = torch.masked_select(x, mask)
print(out)
'''output:
tensor([-0.4761,  0.2151])
'''

#17. 2개의 텐서 결합하기

import torch

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

z1 = torch.cat([x,y], dim=0)
print(z1)
'''
tensor([[ 1.,  2.,  3.],
        [ 4.,  5.,  6.],
        [-1., -2., -3.],
        [-4., -5., -6.]])
'''

z2 = torch.cat([x,y], dim=1)
print(z2)
'''
tensor([[ 1.,  2.,  3., -1., -2., -3.],
        [ 4.,  5.,  6., -4., -5., -6.]])
'''

#18. 2개의 텐서 결합하기(stack 함수)

import torch

x = torch.FloatTensor([[1,2,3],[4,5,6]])
x_stack = torch.stack([x,x,x,x],dim=0)
print(x_stack)
'''
tensor([[[1., 2., 3.],
         [4., 5., 6.]],

        [[1., 2., 3.],
         [4., 5., 6.]],

        [[1., 2., 3.],
         [4., 5., 6.]],

        [[1., 2., 3.],
         [4., 5., 6.]]])
'''

y_stack = torch.stack([x,x,x,x],dim=1)
print(y_stack)
'''
tensor([[[1., 2., 3.],
         [1., 2., 3.],
         [1., 2., 3.],
         [1., 2., 3.]],

        [[4., 5., 6.],
         [4., 5., 6.],
         [4., 5., 6.],
         [4., 5., 6.]]])
'''

#19. 하나의 텐서를 n개로 분해하기

import torch

z1 = torch.FloatTensor([
    [ 1.,  2.,  3.],
    [ 4.,  5.,  6.],
    [-1., -2., -3.],
    [-4., -5., -6.]
])
x_1,x_2 = torch.chunk(z1,2,dim=0)
print(x_1,x_2,sep='\n')
'''
tensor([[1., 2., 3.],
        [4., 5., 6.]])
tensor([[-1., -2., -3.],
        [-4., -5., -6.]])
'''

y_1,y_2 = torch.chunk(z1,2,dim=1)
print(y_1,y_2,sep='\n')
'''
tensor([[ 1.,  2.],
        [ 4.,  5.],
        [-1., -2.],
        [-4., -5.]])
tensor([[ 3.],
        [ 6.],
        [-3.],
        [-6.]])
'''

#20. 하나의 텐서를 분리하기

import torch

z1 = torch.FloatTensor([
    [ 1.,  2.,  3.],
    [ 4.,  5.,  6.],
    [-1., -2., -3.],
    [-4., -5., -6.]
])
x1,x2 = torch.split(z1,2,dim=0)
print(x1,x2,sep='\n')
'''
tensor([[1., 2., 3.],
        [4., 5., 6.]])
tensor([[-1., -2., -3.],
        [-4., -5., -6.]])
'''

y1,y2 = torch.split(z1,2,dim=1)
print(y1,y2,sep='\n')
'''
tensor([[ 1.,  2.],
        [ 4.,  5.],
        [-1., -2.],
        [-4., -5.]])
tensor([[ 3.],
        [ 6.],
        [-3.],
        [-6.]])
'''

y = torch.split(z1,2,dim=1)
for i in y:
    print(i)
'''
tensor([[ 1.,  2.],
        [ 4.,  5.],
        [-1., -2.],
        [-4., -5.]])
tensor([[ 3.],
        [ 6.],
        [-3.],
        [-6.]])
'''

#21. 1개 요소를 갖는 축 제거

import torch

x1 = torch.FloatTensor(10,1,3,1,4)
x2 = torch.squeeze(x1)
print(x1.size(),x2.size()) # torch.Size([10, 1, 3, 1, 4]) torch.Size([10, 3, 4])

#22. unsqueeze 연산

import torch

x1 = torch.FloatTensor(10,3,4)
x2 = torch.unsqueeze(x1, dim=0)
print(x1.size(),x2.size()) # torch.Size([10, 3, 4]) torch.Size([1, 10, 3, 4])

x3 = torch.unsqueeze(x1, dim=1)
print(x1.size(),x3.size()) # torch.Size([10, 3, 4]) torch.Size([10, 1, 3, 4])

#23. 다양한 분포를 갖는 텐서 만들기

import torch
import torch.nn.init as init

x1 = init.uniform_(torch.FloatTensor(3,4),a=0,b=9)
print(x1)

x2 = init.normal_(torch.FloatTensor(3,4),std=0.2)
print(x2)

x3 = init.constant_(torch.FloatTensor(3,4),3.1415926)
print(x3)

#24. 텐서간의 합

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])
x2 = torch.FloatTensor([[1,2,3],[4,5,6]])

add1 = torch.add(x1,x2)
print(add1)

add2 = x1+x2
print(add2)

#25. 텐서의 브로드케스트 합

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])
x2 = x1 + 10
print(x2)

#26. 텐서 요소간의 곱

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])
x2 = torch.FloatTensor([[1,2,3],[4,5,6]])

x3 = torch.mul(x1,x2)
print(x3)
'''
tensor([[ 1.,  4.,  9.],
        [16., 25., 36.]])
'''

x4 = x1*x2
print(x4)
'''
tensor([[ 1.,  4.,  9.],
        [16., 25., 36.]])
'''

#27. 텐서 요소간의 나누기

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])
x2 = torch.FloatTensor([[1,2,3],[4,5,6]])

x3 = torch.div(x1,x2)
print(x3)
'''
tensor([[1., 1., 1.],
        [1., 1., 1.]])
'''

x4 = x1/x2
print(x4)
'''
tensor([[1., 1., 1.],
        [1., 1., 1.]])
'''

#28. 텐서 요소의 제곱

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])

x2 = torch.pow(x1,2)
print(x2)
'''
tensor([[ 1.,  4.,  9.],
        [16., 25., 36.]])
'''

x3 = x1**2
print(x3)
'''
tensor([[ 1.,  4.,  9.],
        [16., 25., 36.]])
'''

#29. 텐서 요소의 지수 연산

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])
x2 = torch.exp(x1)
print(x2)

#30. 텐서 요소의 로그 연산

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])
x2 = torch.log(x1)
print(x2)

#31. 행렬곱

import torch

x1 = torch.FloatTensor([[1,2,3],[4,5,6]])
x2 = torch.FloatTensor([[1,2,3],[4,5,6],[7,8,9]])
x3 = torch.mm(x1,x2)
print(x3)
'''
tensor([[30., 36., 42.],
        [66., 81., 96.]])
'''

#32. 배치 행렬곱 연산(맨 앞에 batch 차원은 유지하면서 뒤에 요소들의 행렬곱)

import torch

x1 = torch.FloatTensor([
    [[1,2,3],[4,5,6]],
    [[1,2,3],[4,5,6]],
])
x2 = torch.FloatTensor([
    [[1,2,3],[4,5,6],[7,8,9]],
    [[1,2,3],[4,5,6],[7,8,9]],
])
x3 = torch.bmm(x1,x2)
print(x3)
'''
tensor([[[30., 36., 42.],
         [66., 81., 96.]],

        [[30., 36., 42.],
         [66., 81., 96.]]])
'''

#33. 벡터의 내적

import torch

x1 = torch.tensor([1,2,3,4])
x2 = torch.tensor([2,3,4,5])
x3 = torch.dot(x1,x2)
print(x3) # tensor(40)

#34. 텐서의 전치

import torch

x1 = torch.tensor([[1,2,3],[4,5,6],[7,8,9]])
print(x1)
x2 = x1.t()
print(x2)

#35. 텐서의 내부 차원 간 바꿈

import torch

hwc_img_data = torch.rand(100, 64, 32, 3)
print(hwc_img_data.size()) # torch.Size([100, 64, 32, 3])
chw_img_data = hwc_img_data.transpose(1,2)
print(chw_img_data.size()) # torch.Size([100, 32, 64, 3])
chw_img_data = chw_img_data.transpose(1,3)
print(chw_img_data.size()) # torch.Size([100, 3, 64, 32])

#36. 벡터의 내적, 행렬과 벡터의 곱, 행렬간 곱

import torch

m = torch.randn(100,10)
v = torch.randn(10)

d = torch.matmul(v,v) # = torch.dot, 벡터의 내적
print(d)

v2 = torch.matmul(m,v) # = torch.mv, 행렬과 벡터의 곱
print(v2)

m2 = torch.matmul(m.t(), m) # = torch.mm, 행렬 곱
print(m2)

#37. 다항분포 확률값 기반의 샘플링

import torch
 
x1 = torch.FloatTensor(
    [
        [1,2,3,4,5,6,7,8,9],
        [9,8,7,6,5,4,3,2,1],
        [1,2,3,4,5,6,7,8,9],
        [9,8,7,6,5,4,3,2,1]
    ]
)
i = torch.multinomial(x1.exp(), 1)
print(i)
'''
output:
tensor([[8],
        [0],
        [7],
        [1]])
'''

torch.multinomial 함수는 2개의 인자를 받는데, 첫번째 인자는 확률로 해석될 수 있는 텐서이고 두번째는 샘플링할 개수이다. 첫번째 인자는 확률로 해석할 수 있지만, 정규화될 필요는 없다. 여기서 정규화란 더해서 1이 되어야 한다는 의미이다. 결과에서 보면 알 수 있듯이 샘플링된 값의 인덱스 값이 반환된다.

#38. 상위 n개 가져오기

import torch
 
x = torch.rand(10)
print(x) # tensor([0.9097, 0.3766, 0.6321, 0.0760, 0.0137, 0.1760, 0.0655, 0.7696, 0.5172, 0.4140])

scores, indices = torch.topk(x, 3)

for i in range(0,3):
    print(indices[i].item(), scores[i].item())
'''output:
0 0.909696102142334
7 0.769554853439331
2 0.6320836544036865
'''

PyTorch의 Dataset과 DataLoader를 이용하여 학습 효율성 향상시키기

PyTorch의 Dataset과 DataLoader를 이용하면 학습을 위한 방대한 데이터를 미니배치 단위로 처리할 수 있고, 데이터를 무작위로 섞음으로써 학습의 효율성을 향상시킬 수 있다. 또한 데이터를 여러개의 GPU를 사용해 병렬처리로 학습할 수도 있다. 아래의 코드는 Dataset과 DataLoader를 사용하지 않고 매 에폭마다 학습 데이터 전체를 입력해 학습하는 코드이다.

import torch
from torch import nn, optim
from sklearn.datasets import load_iris
from torch.utils.data import  TensorDataset, DataLoader
 
iris = load_iris()
 
X = iris.data[:100]
y = iris.target[:100]
 
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32)
 
net = nn.Linear(4, 1)
loss_fn = nn.BCEWithLogitsLoss()
optimizer = optim.SGD(net.parameters(), lr=0.25)
 
losses = []
 
for epoc in range(100):
    batch_loss = 0.0

    optimizer.zero_grad()
    y_pred = net(X)
    loss = loss_fn(y_pred.view_as(y), y)
    loss.backward()
    optimizer.step()
    batch_loss += loss.item()
    
    losses.append(batch_loss)
 
from matplotlib import pyplot as plt
plt.plot(losses)
plt.show()

위의 코드에 대한 손실 그래프는 다음과 같다.

다음 코드는 위의 코드에 대해서 Dataset과 DataLoader를 적용한 코드이다. 앞 코드의 하이퍼 파라메터 등에 대한 모든 조건은 동일하고 단지 미니배치를 10로 하여 학습시킨다.

import torch
from torch import nn, optim
from sklearn.datasets import load_iris
from torch.utils.data import  TensorDataset, DataLoader

iris = load_iris()

X = iris.data[:100]
y = iris.target[:100]

X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.float32)

ds = TensorDataset(X, y)
loader = DataLoader(ds, batch_size=10, shuffle=True)

net = nn.Linear(4, 1)
loss_fn = nn.BCEWithLogitsLoss()
optimizer = optim.SGD(net.parameters(), lr=0.25)

losses = []

for epoc in range(100):
    batch_loss = 0.0
    for xx, yy in loader:
        optimizer.zero_grad()
        y_pred = net(xx)
        loss = loss_fn(y_pred.view_as(yy), yy)
        loss.backward()
        optimizer.step()
        batch_loss += loss.item()
    losses.append(batch_loss)

from matplotlib import pyplot as plt
plt.plot(losses)
plt.show()

위의 코드에 대한 손실 그래프는 다음과 같다.

손실 그래프를 보면 미니배치를 사용한 것이 더 안정적으로 학습이 진행 되는 것으로 확인할 수 있다.

선형회귀모델에 대한 PyTorch를 이용한 두가지 접근

아래와 같은 식을 회귀하는 모델을 구하는 두가지 접근을 PyTorch로 살펴본다.

    $$y=1+5a+7b$$

즉, 입력값(a, b)에 대한 출력값 y가 100개 주어지고, 이 데이터를 통해 상수항인 1과 계수 5, 7을 구하는 것이 문제다. 물론 y에는 오차가 반영되어 있다. 첫번째 접근은 다음과 같다. 손실함수는 평균최소제곱을, 역전파를 통한 최적값 수렴을 위한 기울기를 구해 반영한 학습률은 0.01을 사용했다. 아래의 코드의 경우 기울기를 구하기 위한 방법을 PyTorch의 역전파를 이용한 것이다.

import torch
from matplotlib import pyplot as plt

weight_true = torch.Tensor([1,5,7]) # y = 1 + 5a + 7b
X = torch.cat([torch.ones(100,1),torch.randn(100,2)], 1)
y = torch.mv(X, weight_true) + torch.randn(100)
weight = torch.randn(3, requires_grad=True)

lr = 0.01

losses = []

for epoch in range(1000):
    weight.grad = None

    y_pred = torch.mv(X, weight)
    loss = torch.mean((y - y_pred)**2)
    loss.backward()

    weight.data = weight.data - lr*weight.grad.data

    losses.append(loss.item())

print(weight)

plt.plot(losses)
plt.show()

두번째 접근은 다음과 같다. 앞서 직접 하나 하나 개발자가 지정했던 것들에 대한 모듈을 사용한 경우이다.

import torch
from torch import nn, optim
from matplotlib import pyplot as plt

weight_true = torch.Tensor([1,5,7]) # y = 1 + 5a + 7b
X = torch.cat([torch.ones(100,1),torch.randn(100,2)], 1)
y = torch.mv(X, weight_true) + torch.randn(100)

net = nn.Linear(in_features=3, out_features=1, bias=False)
optimizer = optim.SGD(net.parameters(), lr=0.01)
loss_fn = nn.MSELoss()

losses = []

for epoch in range(1000):
    optimizer.zero_grad()

    y_pred = net(X)
    loss = loss_fn(y_pred.view_as(y), y)
    loss.backward()

    optimizer.step()

    losses.append(loss.item())

print(net.weight)

plt.plot(losses)
plt.show()

두 경우 모두 실행하면 아래와 같은 손실값에 대한 그래프와 추론된 상수와 두계수 값이 콘솔에 출력된다.

tensor([0.9295, 4.9402, 7.0627], requires_grad=True)

함수들에 대한 그래프 시각화

선형 함수에 대한 정의와 그래프 시각화는 다음 코드와 같다.

import numpy as np
import matplotlib.pylab as plt

def identity_func(x):
    return x

x = np.arange(-10, 10, 0.01)
plt.plot(x, identity_func(x), linestyle='-', label="identity")
plt.ylim(-10, 10)
plt.legend()
plt.show() 

결과는 다음과 같다.

기울기와 y절편을 고려한 선형 함수의 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
  
def linear_func(x):
    return 2 * x + 1 
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, linear_func(x), linestyle='-', label="linear_func")
plt.ylim(-10, 10)
plt.legend()
plt.show() 

결과는 다음과 같다.

계단함수에 대한 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def binarystep_func(x):
    return (x>=0)*1
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, binarystep_func(x), linestyle='-', label="binarystep_func")
plt.ylim(-5, 5)
plt.legend()
plt.show() 

결과는 다음과 같다.

로지스틱(Logistic) 또는 시그모이드(Sigmoid)라고 불리는 함수 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt

def softstep_func(x):
    return 1 / (1 + np.exp(-x))

x = np.arange(-10, 10, 0.01)
plt.plot(x, softstep_func(x), linestyle='-', label="softstep_func")
plt.ylim(0, 1)
plt.legend()
plt.show()     

결과는 다음과 같다.

TanH 함수 정의 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def tanh_func(x):
    return np.tanh(x)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, tanh_func(x), linestyle='-', label="tanh_func")
plt.ylim(-1, 1)
plt.legend()
plt.show()     

그래프는 다음과 같다.

ArcTan 함수 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt

def arctan_func(x):
    return np.arctan(x)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, arctan_func(x), linestyle='-', label="arctan_func")
plt.ylim(-1.5, 1.5)
plt.legend()
plt.show()     

그래프는 다음과 같다.

Soft Sign 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def softsign_func(x):
    return x / ( 1+ np.abs(x) )
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, softsign_func(x), linestyle='-', label="softsign_func")
plt.ylim(-1, 1)
plt.legend()
plt.show()     

그래프는 다음과 같다.

ReLU(Rectified Linear Unit) 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def relu_func(x):
    return (x>0)*x
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, relu_func(x), linestyle='-', label="relu_func")
plt.ylim(-1, 11)
plt.legend()
plt.show()     

결과는 다음과 같다.

Leaky ReLU 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def leakyrelu_func(x, alpha=0.1):
    return (x>=0)*x + (x<0)*alpha*x
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, leakyrelu_func(x), linestyle='-', label="leakyrelu_func")
plt.ylim(-2, 11)
plt.legend()
plt.show()   

결과는 다음과 같다.

ELU(Exponential Linear Unit) 함수는 다음과 같다.

def elu_func(x, alpha=0.9):
    return (x>=0)*x + (x<0)*alpha*(np.exp(x)-1)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, elu_func(x), linestyle='-', label="elu_func")
plt.ylim(-2, 11)
plt.legend()
plt.show()    

결과는 다음과 같다.

TreLU 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def trelu_func(x, thres=2):
    return (x>thres)*x
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, trelu_func(x), linestyle='-', label="trelu_func")
plt.ylim(-2, 11)
plt.legend()
plt.show()     

결과는 다음과 같다.

SoftPlus 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def softplus_func(x):
    return np.log( 1 + np.exp(x) )
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, softplus_func(x), linestyle='-', label="softplus_func")
plt.ylim(-1, 11)
plt.legend()
plt.show()     

결과는 다음과 같다.

Bent identity 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def bentidentity_func(x):
    return (np.sqrt(x*x+1)-1)/2+x

x = np.arange(-10, 10, 0.01)
plt.plot(x, bentidentity_func(x), linestyle='-', label="bentidentity_func")
plt.ylim(-6, 11)
plt.legend()
plt.show()

결과는 다음과 같다.

Gaussian 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def gaussian_func(x):
    return np.exp(-x*x)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, gaussian_func(x), linestyle='-', label="gaussian_func")
plt.ylim(-0.5, 1.5)
plt.legend()
plt.show()

결과는 다음과 같다.