import numpy        # 배열의 이용을 위해 넘파이 호출
import matplotlib.pyplot   # 맷플롯립.파이플롯 > 데이터 시각화를 위한 파이썬 확장 라이브러리

data_file = open('mnist_dataset/mnist_train_100.csv', 'r')
data_list = data_file.readlines() # CSV 의 내용을 변수로 저장, 인덱스로 접근가능, data_list[1]
print(data_list[0])     # 0번째 데이터 불러오기
print(data_list[1])     # 1번째 데이터 불러오기
print(data_list[2:6])   # 2~5번째 데이터 불러오기

'''
위 값을 사용하기 위해서는 
1. 구분자를 쉼표를 이용해 긴 텍스트 문자열을 개별 값으로 분리한다.
2. 레이블 값인 첫 번째 값(답)은 무시하고 나머지 28 X 28 = 784 의 값을 추출한 후,
    이를 28개 행과 28개 열의 형태를 가지는 배열로 변환해준다.
3. 이 배열을 시각화 한다.
'''


all_values = data_list[0].split(',')    # 쉼표로 구분된 숫자들의 리스트를 적절한 행렬(넘파이)로 변환
image_array = numpy.asfarray(all_values[1:]).reshape((28,28))
# numpy.asfarray > numpy 함수로서 문자열을 실수로 변환(*읽어진 파일은 모두 문자열이다) / 1번째부터 끝까지. 28*28 형태 배열로 변환
matplotlib.pyplot.imshow(image_array, cmap='rainbow', interpolation='None')
# imshow 함수를 이용해 image_array 를 시각화 / 가독성을 위해 cmap = 'Greys' 를 지정해 회색톤의 색상 팔레트 사용 / ('rainbow') 로 확인가능

'''
입력 데이터와 출력 데이터의 값들이 적절한 형태를 가져서 
활성화 함수의 수용 범위 내에 있게 되면 신경망은 더 잘 작동하게 된다.
0 ~ 255 사이에 속하는 입력 색상 값들의 범위를 0.01 ~ 1.0 사이에 속하게 조정하면 된다.
이 때, 입력 값이 0을 가지면 가중치 업데이트를 없애버리므로 범위의 하한선은 0.01로 선택하였다.

하지만 입력 값이 1.0 인 것은 별 문제가 되지 않기 때문에 범위의 상한선은 1.0으로 선택했다.
출력 값에 대해서는 1.0을 피해야한다.

따라서
1. 0 ~ 255 사이의 값을 가지는 입력 값들을 255로 나누면 0 ~ 1 의 범위를 가진다.
2. 여기에 0.99 를 곱하면 그 범위는 0.0 ~ 0.99가 된다.
3. 여기에 0.01 을 더함으로 원하는 범위인 0.01 ~ 1.00 을 얻을 수 있다.

이를 코드로 하면
'''

scaled_input = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
print(scaled_input)

'''
결과 값이 활성화 함수가 출력할 수 있는 값의 범위 내에 있어야 하기 때문에
우리가 이용할 로지스틱 함수는 -2.0이나 255 같은 값을 출력할 수 없다.
(로지스틱 회귀는 데이터가 어떤 범주에 속할 확률을 0에서 1사이의 값으로 예측하고 그 확률에 따라
가능성이 더 높은 범주에 속하는 것으로 분류해주는 지도 학습 알고리즘이다.
그 범위는 0.0 ~ 1.0 사이인데, 0.0 과 1.0 에는 무한히 접근만 할 뿐 실제 0.0이나 1.0이 될 수는 없다.
따라 결과 값의 범위를 조정해야한다.

결과 값이 어떻게 나와야하는지 생각해보자.
결과 값이 정답의 이미지가 되어야하면 28 * 28 즉, 784 개의 출력 노드가 필요하다.

하지만 우리가 원하는 것은 정답 이미지가 아닌, 
이미지를 분류해 정확한 레이블을 할당하는 것이다.
레이블은 0 ~ 9 까지 10개 숫자 중 하나이며, 
10개의 노드로 구성된 출력 계층이 필요하다.

각 노드는 가능한 결과 값, 즉 각 레이블에 해당한다.

'''

'''
첫 번째 결과 예는 신경망이 숫자 5를 봤다고 판단합니다.
출력 계층에서 신호가 가장 큰 노드는 레이블 5에 해당하는 노드이기 때문입니다.
이 때 로지스틱 회귀 분석을 통해 각 노드에 대해 2진 분류를 진행하게 되고 
유사 정도에 따라 0이나 1에 가까운 값을 반환합니다.
3번째 예에서는 9에서 최대 출력을 갖지만 4에서도 상당한 출력값을 가집니다.
이 경우 신경망이 4일 가능성도 있다고 부분적으로 판단한 것인데,
신경망 작업 시 이런 불확실성이 종종 일어납니다.
이런 불확실성은 다른 답에 대한 가능성이라 생각하는게 좋습니다.

'''

'''
이러한 출력 결과를 행렬로 구체화하면
만약 학습 데이터의 레이블이 5일 때,

1. 결과 값 행렬을 만들 때 5에 상응하는 노드(1) 외에는 작은 값(0)을 가져야합니다.
2. 활성화 함수가 도달할 수 없는 0과 1이라는 값을 사용하게 되면 신경망이 포화됩니다.
3. 따라 0.01 ~ 0.99 범위를 적용해야 합니다.

이를 파이썬 코드로 표현하면
'''

onodes = 10     # 출력 노드는 10개
targets = numpy.zeros(onodes) + 0.01        # 모든 노드를 0으로 세팅하고 0.01을 더함
targets[int(all_values[0])] = 0.99          # 레코드 첫번째 인덱스, 즉 레이블을 정수형으로 변환하고 인덱스를 받은 후, 0.99로 세팅한다.
print(targets)
