[ Deep Dive ] divergence.

d4r6j·2024년 6월 25일

error log

목록 보기
3/3
post-thumbnail

overview

sum 을 할 경우 clip 혹은 max 등 넘칠 경우에 문제가 발생할 수 있다고 생각했다.

divergence 에 대한 분석 참고.

  • 실제로 activation function 을 직접 설계 한 후 torch framework 에 끼어 넣었다.
  • gradient 시에 inf 를 만나서 훈련 중 끊어지는 상황을 본 적이 있다.

다시 생각해보면, nn.Conv2d 를 사용할 경우, torch framework 안에서 놀기 때문에 문제는 없다.

self.conv = nn.Conv2d(c1, 1, 1, bias=False).requires_grad_(False)

이와 같이 requires_grad 로 backprop 시에 gradient 를 하지 않아서 문제는 없다.

허나, 저 당시 좀 더 다루지 못했던 부분을 다루어볼 생각이다.

about inf

앞에서 체크된 range 를 다시 보자.

>>> torch.log(torch.tensor([1e-45]))
tensor([-103.2789])
>>> torch.log(torch.tensor([1e-46]))
tensor([-inf])

실제 activation 때 이렇게 되었는데,

>>> torch.tensor([1e-200])
tensor([0.])

하지만 log\log00 에 가까워지면-inf 가 나오는건 당연하지만..

denormalized value

numeric limits 정의 참고. (cpp-reference)

float max_value = std::numeric_limits<float>::max();	
std::cout << "max_value: " << max_value << std::endl;

float max_value_2nd = 3.40283e+38;
std::cout << "max_value_2nd: " << max_value_2nd << std::endl;

float min_value = std::numeric_limits<float>::min();
std::cout << "min_value: " << min_value << std::endl;

float min_value_2nd = 1.17548e-38;
std::cout << "min_value_2nd: " << min_value_2nd << std::endl;

float lowest_value = std::numeric_limits<float>::lowest();
std::cout << "lowest_value: " << lowest_value << std::endl;

result

max_value: 3.40282e+38
max_value_2nd: inf
min_value: 1.17549e-38
min_value_2nd: 1.17548e-38
lowest_value: -3.40282e+38
  • min() 는 생각해보면 0 에 가까워질 뿐, positive value 로 아주 작게 가능하다.

실제 모든 numeric 에 관해서 이런 limitation 이 존재한다.

/usr/include/limits.h 참고

// ...

/* Minimum and maximum values a `signed short int' can hold.  */
#  define SHRT_MIN  (-32768)
#  define SHRT_MAX  32767

/* Maximum value an `unsigned short int' can hold.  (Minimum is 0.)  */
#  define USHRT_MAX 65535

/* Minimum and maximum values a `signed int' can hold.  */
#  define INT_MIN   (-INT_MAX - 1)
#  define INT_MAX   2147483647

/* Maximum value an `unsigned int' can hold.  (Minimum is 0.)  */
#  define UINT_MAX  4294967295U

/* Minimum and maximum values a `signed long int' can hold.  */
#  if __WORDSIZE == 64
#   define LONG_MAX 9223372036854775807L
#  else
#   define LONG_MAX 2147483647L
#  endif
#  define LONG_MIN  (-LONG_MAX - 1L)

// ...

그럼 의문이 드는 것은 set 의 정의가 (0,N](0, N] 으로 0 의 boundary 가 열린 집합일 때, 어디까지 가능할까? 가 의문이 든다.

min value

max_value: 3.40282e+38
min_value: 1.17549e-38

로 되어 있지만 min_value 는 더 내려갈 수 있다. 0 에 더 가까워 질 수 있다는 말이 맞다.

>>> torch.log(torch.tensor([1e-45]))
tensor([-103.2789])

>>> torch.log(torch.tensor([1e-46]))
tensor([-inf])

>>> torch.tensor(1e-45)
tensor(1.4013e-45)

>>> torch.tensor(1e-46)
tensor(0.)

비교 값 코드

// compare_f1
float compare_f1 = 1e-45;
std::cout << "compare_f1: " << compare_f1 << std::endl;

// compare_f2 
float compare_f2 = 1e-46;
std::cout << "compare_f2: " << compare_f2 << std::endl;

// compare_d1 
double compare_d1 = 1e-45;
std::cout << "compare_d1: " << compare_d1 << std::endl;

// compare_d1 : 
double compare_d2 = 1e-46;
std::cout << "compare_d2: " << compare_d2 << std::endl;
compare_f1: 1.4013e-45
compare_f2: 0
compare_d1: 1e-45
compare_d2: 1e-46

stl

// STL/stl/inc/limits

static constexpr int digits         = FLT_MANT_DIG;
static constexpr int digits10       = FLT_DIG;
static constexpr int max_digits10   = 9;
static constexpr int max_exponent   = FLT_MAX_EXP;
static constexpr int max_exponent10 = FLT_MAX_10_EXP; // 38
static constexpr int min_exponent   = FLT_MIN_EXP;
static constexpr int min_exponent10 = FLT_MIN_10_EXP; // -37
max_value: 3.40282e+38
min_value: 1.17549e-38

로도 확인 할 수 있다.

result

torch framework 에서 사용할 경우, torch 안의 함수를 사용하여 quantized (clip, clamp) 을 적용하게 받거나, 실제 만들어서 적용하려면 이와 같은 numeric limitation 을 신경 써서 작업해야 문제가 없다.

현재는 GPU 가 중심이고, 미분 계산기에 의존 하지만, 이런 체계들이 근본이다.

ref

namu.wiki, 컴퓨터의 수 표현

0개의 댓글