1. 개요
이 튜토리얼이 Tensorflow 2.2에 맞게 업데이트되었습니다.
이 Codelab에서는 필기 입력된 숫자를 인식하는 신경망을 빌드하고 학습시키는 방법을 알아봅니다. 그 과정에서 99% 의 정확성을 달성하기 위해 신경망을 개선하면서 딥 러닝 전문가가 모델을 효율적으로 학습시키는 데 사용하는 업계 도구도 발견하게 될 것입니다.
이 Codelab에서는 MNIST 데이터 세트를 사용합니다. 이 데이터 세트는 라벨이 지정된 60, 000개의 숫자 모음으로,거의 20년 동안 여러 세대의 박사 학위 과정을 바쳤습니다. 100줄 미만의 Python / TensorFlow 코드로 문제를 해결합니다.
학습할 내용
- 신경망의 정의 및 학습 방법
- tf.keras를 사용하여 기본적인 1레이어 신경망을 빌드하는 방법
- 레이어를 더 추가하는 방법
- 학습률 일정을 설정하는 방법
- 컨볼루셔널 신경망 빌드 방법
- 정규화 기법 사용 방법: 드롭아웃, 배치 정규화
- 과적합이란?
필요한 항목
브라우저만 있으면 됩니다. 이 워크숍은 전적으로 Google Colaboratory를 통해 진행할 수 있습니다.
의견
이 실습에서 부족한 부분이 있거나 개선이 필요하다고 생각되는 부분이 있으면 알려 주세요. YouTube는 GitHub 문제[의견 링크]를 통해 의견을 처리합니다.
2. Google Colaboratory 빠른 시작
이 실습에서는 Google Colaboratory를 사용하므로 사용자가 별도로 설정할 필요가 없습니다. Chromebook에서 실행할 수 있습니다. 아래 파일을 열고 셀을 실행하여 Colab 노트북에 익숙해지세요.
추가 안내는 아래를 참고하세요.
GPU 백엔드 선택
Colab 메뉴에서 런타임 > 런타임 유형 변경을 선택한 다음 GPU를 선택합니다. 처음 실행 시 런타임에 자동으로 연결이 이루어집니다. 또는 '연결' 버튼을 클릭합니다.
노트북 실행
셀을 클릭하고 Shift-Enter를 사용하여 셀을 한 번에 하나씩 실행합니다. 런타임 > 모두 실행
목차
모든 노트북에는 목차가 있습니다. 왼쪽에 있는 검은색 화살표를 사용해 파일을 열 수 있습니다.
숨겨진 셀
일부 셀에는 제목만 표시됩니다. Colab 전용 노트북 기능입니다. 두 번 클릭하면 안의 코드를 볼 수 있지만 보통은 그다지 흥미롭지 않습니다. 일반적으로 지원 또는 시각화 함수입니다. 내부의 함수를 정의하려면 이러한 셀을 실행해야 합니다.
3. 신경망 학습시키기
먼저 신경망 트레인을 살펴보겠습니다. 아래 노트북을 열고 모든 셀을 실행하세요. 코드는 나중에 설명하겠습니다. 아직 코드는 주의를 기울이지 마세요.
노트북을 실행할 때 시각화에 집중합니다. 설명은 아래를 참조하세요.
학습 데이터
각 사진이 무엇을 나타내는지 알 수 있도록 라벨이 지정된 필기 입력 숫자 데이터 세트가 있습니다. 즉, 0과 9 사이의 숫자입니다. 노트북에 발췌 부분이 표시됩니다.
빌드할 신경망은 필기 입력된 숫자를 10개 클래스 (0, .., 9)로 분류합니다. 이는 분류가 제대로 작동하려면 올바른 값을 가져야 하는 내부 매개변수를 기반으로 합니다. 이 '올바른 값' '라벨이 지정된 데이터 세트'가 필요한 학습 프로세스를 통해 학습됩니다 이미지 및 관련 정답이 표시됩니다
학습된 신경망의 성능이 좋은지 여부를 어떻게 알 수 있을까요? 학습 데이터 세트를 사용하여 네트워크를 테스트하는 것은 부정행위가 됩니다. 이미 학습 중에 해당 데이터 세트를 여러 번 확인했으며, 가장 높은 성능을 발휘합니다. '실제 세계'를 평가하려면 학습 중에는 볼 수 없는 라벨이 지정된 또 다른 데이터 세트가 필요합니다. 네트워크 성능의 영향을 받습니다 이를 '검증 데이터 세트'라고 합니다.
교육
학습이 진행됨에 따라 한 번에 한 배치의 학습 데이터가 업데이트되고, 내부 모델 매개변수가 업데이트되고, 모델은 필기 입력된 숫자를 인식하는 능력이 점점 더 좋아집니다. 학습 그래프에서 이를 확인할 수 있습니다.
오른쪽에는 'accuracy' 올바르게 인식된 숫자의 비율입니다. 학습이 진행됨에 따라 상승하므로 좋은 현상입니다.
왼쪽에서 'loss'를 확인할 수 있습니다. 학습을 유도하기 위해 '손실'을 정의합니다. 함수를 사용하여 숫자를 최소화합니다. 여기서 볼 수 있듯이 손실은 학습이 진행됨에 따라 학습 데이터와 검증 데이터 모두에서 감소합니다. 신경망이 학습 중임을 의미합니다.
X축은 '에포크'의 수를 나타냄 전체 데이터 세트를 통해 반복할 수 있습니다
예측
모델이 학습되면 모델을 사용하여 필기 입력된 숫자를 인식할 수 있습니다. 다음 시각화는 로컬 글꼴 (첫 번째 줄)에서 렌더링된 몇 자릿수와 검증 데이터 세트 10,000자리에서 렌더링된 성능을 보여줍니다. 예측된 클래스는 각 숫자 아래에 빨간색으로 표시되고, 잘못되었다면 빨간색으로 표시됩니다.
보시다시피 이 초기 모델은 그다지 좋지 않지만 여전히 일부 숫자를 올바르게 인식합니다. 최종 검증 정확성은 약 90% 로, 지금 가고 있는 단순한 모델로서는 그리 나쁘지 않지만 여전히 10,000개 중에서 1,000개의 검증 숫자를 놓친다는 의미입니다. 더 많은 정보를 표시할 수 있기 때문에 모든 답이 틀린 것 (빨간색)처럼 보입니다.
텐서
데이터는 행렬에 저장됩니다. 28x28픽셀의 그레이 스케일 이미지는 28x28 2차원 행렬에 들어갑니다. 하지만 컬러 이미지의 경우 더 많은 차원이 필요합니다. 픽셀당 색상 값 3개 (빨간색, 녹색, 파란색)가 있으므로 측정기준이 [28, 28, 3]인 3차원 표가 필요합니다. 또한 128가지 색상의 이미지를 일괄 저장하려면 크기가 [128, 28, 28, 3]인 4차원 표가 필요합니다.
이러한 다차원 표를 '텐서'라고 하며 측정기준 목록을 '형상'이라고 합니다.
4. [정보]: 신경망 기초
요약
다음 단락에서 굵게 표시된 모든 용어를 이미 알고 있는 경우 다음 실습으로 이동할 수 있습니다. 딥 러닝을 이제 막 시작했다면 환영하며, 계속 읽어 보시기 바랍니다.
레이어의 시퀀스로 빌드된 모델의 경우 Keras는 Sequential API를 제공합니다. 예를 들어 밀집 레이어 3개를 사용하는 이미지 분류기는 Keras로 다음과 같이 작성할 수 있습니다.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28, 1]),
tf.keras.layers.Dense(200, activation="relu"),
tf.keras.layers.Dense(60, activation="relu"),
tf.keras.layers.Dense(10, activation='softmax') # classifying into 10 classes
])
# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy']) # % of correct answers
# train the model
model.fit(dataset, ... )
단일 밀집 레이어
MNIST 데이터 세트의 필기 입력 숫자는 28x28픽셀의 그레이 스케일 이미지입니다. 이를 분류하는 가장 간단한 방법은 28x28=784 픽셀을 1계층 신경망의 입력으로 사용하는 것입니다.
신경망의 각 '뉴런'은 모든 입력의 가중 합계를 구하고 '편향'이라는 상수를 더합니다. 그런 다음 비선형 '활성화 함수'를 통해 결과를 제공합니다. "weights" 및 "biases"는 학습을 통해 결정되는 매개변수입니다. 처음에는 임의의 값으로 초기화됩니다.
위의 그림은 숫자를 10개의 클래스 (0~9)로 분류하려고 하므로 10개의 출력 뉴런이 있는 1계층 신경망을 나타냅니다.
행렬 곱셈 사용
이미지 컬렉션을 처리하는 신경망 레이어를 행렬 곱셈으로 표현할 수 있는 방식은 다음과 같습니다.
가중치 행렬 W의 첫 번째 가중치 열을 사용하여 첫 번째 이미지의 모든 픽셀에 대한 가중 합계를 계산합니다. 이 합계는 첫 번째 뉴런에 해당합니다. 두 번째 가중치 열을 사용하여 두 번째 뉴런에도 동일한 작업을 수행하여 10번째 뉴런까지 계속 반복합니다. 그런 다음 나머지 99개의 이미지에 대해 이 작업을 반복할 수 있습니다. 100개의 이미지를 포함하는 행렬인 X를 호출하면 100개의 이미지에 대해 계산된 10개의 뉴런에 대한 가중치가 적용된 모든 합계는 행렬 곱셈인 X.W입니다.
이제 각 뉴런이 편향 (상수)을 추가해야 합니다. 뉴런이 10개이므로 편향 상수는 10개입니다. 값이 10인 이 벡터를 b라고 하겠습니다. 이전에 계산된 행렬의 각 줄에 추가해야 합니다. '방송'이라는 마법을 사용해 보세요. 간단한 더하기 기호로 작성합니다.
마지막으로 '소프트맥스'와 같은 활성화 함수를 적용합니다. (아래 설명 참조)하고 100개의 이미지에 적용된 단일 레이어 신경망을 설명하는 수식을 구합니다.
Keras 사용 시
Keras와 같은 상위 수준 신경망 라이브러리를 사용하면 이 공식을 구현할 필요가 없습니다. 하지만 신경망 레이어는 수많은 곱셈과 덧셈의 조합이라는 것을 이해하는 것이 중요합니다. Keras에서 밀집 레이어는 다음과 같이 작성됩니다.
tf.keras.layers.Dense(10, activation='softmax')
자세히 살펴보기
신경망 레이어를 연결하는 작업은 간단합니다. 첫 번째 레이어는 픽셀의 가중 합계를 계산합니다. 후속 레이어는 이전 레이어 출력의 가중치가 적용된 합계를 계산합니다.
뉴런 수를 제외하고 유일한 차이점은 활성화 함수를 선택하는 것입니다.
활성화 함수: relu, 소프트맥스, 시그모이드
일반적으로 'relu'를 사용합니다. 활성화 함수를 사용해야 합니다. 분류기의 마지막 레이어는 '소프트맥스'를 사용합니다. 활성화해야 합니다.
다시 말하지만, '뉴런'은 모든 입력의 가중 합계를 계산한 다음 '편향'이라는 값을 더합니다. 활성화 함수를 통해 결과를 제공합니다.
가장 많이 사용되는 활성화 함수는 정류 선형 유닛의 'RELU'입니다. 위의 그래프에서 볼 수 있듯이 매우 간단한 함수입니다.
신경망의 전통적인 활성화 함수는 '시그모이드'였지만 '렐루'는 은 거의 모든 곳에서 수렴 특성이 더 나은 것으로 확인되었으며 현재 선호됩니다.
분류를 위한 소프트맥스 활성화
신경망의 마지막 레이어에는 뉴런이 10개 있습니다. 손으로 쓴 숫자를 10개의 클래스 (0,..9)로 분류하려고 하기 때문입니다. 이 자릿수가 0, 1, 2 등이 될 확률을 나타내는 0과 1 사이의 숫자 10개를 출력해야 합니다. 이를 위해 마지막 레이어에서 '소프트맥스'라는 활성화 함수를 사용합니다.
벡터에 소프트맥스를 적용하려면 각 요소의 지수를 구한 다음 벡터를 'L1'로 나누는 방식으로 정규화합니다. norm (절대값의 합)을 구하여 정규화된 값의 합이 1이 되어 확률로 해석될 수 있도록 합니다.
활성화 전 마지막 레이어의 출력을 '로지트'라고도 합니다. 이 벡터가 L = [L0, L1, L2, L3, L4, L5, L6, L7, L8, L9] 인 경우:
교차 엔트로피 손실
이제 신경망이 입력 이미지에서 예측을 생성하므로 얼마나 좋은지 측정해야 합니다. 즉, 네트워크가 알려준 내용과 종종 '라벨'이라고 하는 정답 사이의 거리를 측정해야 합니다. 데이터 세트의 모든 이미지에 올바른 라벨이 있다는 점을 기억하세요.
모든 거리가 작동하지만 분류 문제의 경우 '교차 엔트로피 거리'가 가장 효과적입니다. 이를 오류 또는 '손실'이라고 하겠습니다. 함수:
경사하강법
"학습" 신경망은 실제로 학습 이미지와 라벨을 사용하여 교차 엔트로피 손실 함수를 최소화하기 위해 가중치와 편향을 조정하는 것을 의미합니다. 작동 원리는 다음과 같습니다.
교차 엔트로피는 가중치, 편향, 학습 이미지의 픽셀 및 알려진 클래스의 함수입니다.
모든 가중치와 모든 편향에 상대적인 교차 엔트로피의 편미분을 계산하면 주어진 이미지, 라벨, 가중치와 편향의 현재 값에 대해 계산된 '경사'를 얻게 됩니다. 수백만 개의 가중치와 편향이 있을 수 있으므로 경사를 계산하는 것은 엄청난 노력으로 들립니다. 다행히도 TensorFlow가 자동으로 이 작업을 수행합니다. 그라데이션의 수학적 특성은 '위쪽'을 향한다는 것입니다. 교차 엔트로피가 낮은 곳으로 가려고 하므로 반대 방향으로 갑니다. 가중치와 편향은 경사의 비율로 업데이트합니다. 그런 다음 학습 루프에서 다음 학습 이미지 및 라벨 배치를 사용하여 동일한 작업을 반복해서 수행합니다. 이 경우 교차 엔트로피가 최소 수준인 지점으로 연결되길 바라지만 이 최솟값이 고유하다는 것을 보장하지는 않습니다.
미니 배치 및 모멘텀
예시 이미지 한 개에 대해서만 경사를 계산하고 가중치와 편향을 즉시 업데이트할 수 있지만, 예를 들어 128개 이미지 배치에서는 그라데이션이 적용되어 서로 다른 예시 이미지가 주는 제약 조건을 더 잘 표현하는 그라데이션이 제공되므로 솔루션을 향해 더 빠르게 수렴할 수 있습니다. 미니 배치의 크기는 조정 가능한 매개변수입니다.
'확률적 경사하강법'이라고도 하는 이 기법 또 다른 실용적인 이점이 있습니다. 배치 작업은 더 큰 행렬로 작업하게 되어 일반적으로 GPU 및 TPU에서 더 쉽게 최적화할 수 있다는 것입니다.
하지만 수렴은 여전히 약간 혼란스러울 수 있으며 경사 벡터가 모두 0이면 멈출 수도 있습니다. 최솟값을 찾았다는 뜻일까요? 항상 그렇지는 않습니다. 그라데이션 구성요소는 최솟값이나 최댓값이 0일 수 있습니다. 수백만 개의 요소가 있는 경사 벡터에서 요소가 모두 0인 경우 모든 0이 최솟값에 해당하고 어느 것도 최댓값에 해당하지 않을 확률은 매우 작습니다. 여러 차원의 공간에서 안장점은 매우 일반적이며 여기서 멈추고 싶지 않습니다.
삽화: 새들 포인트 경사는 0이지만 모든 방향에서 최솟값은 아닙니다. (이미지 저작자 표시 Wikimedia: By Nicoguaro - own work, CC BY 3.0)
해결책은 최적화 알고리즘에 모멘텀을 더하여 멈추지 않고 안장 지점을 지나 항해할 수 있도록 하는 것입니다.
용어집
배치 또는 미니 배치: 항상 학습 데이터 및 라벨 배치에 대해 학습이 수행됩니다. 이렇게 하면 알고리즘이 수렴되는 데 도움이 됩니다. '배치' 차원은 일반적으로 데이터 텐서의 첫 번째 차원입니다. 예를 들어 형태가 [100, 192, 192, 3] 인 텐서에는 픽셀당 3개의 값 (RGB)이 있는 192x192픽셀 이미지 100개가 포함됩니다.
교차 엔트로피 손실: 분류기에서 자주 사용되는 특수한 손실 함수입니다.
밀집 레이어: 각 뉴런이 이전 레이어의 모든 뉴런과 연결되는 뉴런 레이어입니다.
특성: 신경망의 입력을 '특성'이라고 부르기도 합니다. 좋은 예측을 하기 위해 데이터 세트의 어떤 부분 (또는 부분의 조합)을 신경망에 입력해야 하는지 알아내는 기술을 '특성 추출'이라고 합니다.
labels: '클래스'의 다른 이름 지도 분류 문제에서 정답과 같은
학습률: 학습 루프의 각 반복에서 가중치와 편향이 업데이트되는 경사의 비율입니다.
로지트: 활성화 함수가 적용되기 전의 뉴런 레이어의 출력을 '로지트'라고 합니다. 이 용어는 '로지스틱 함수'에서 유래했습니다. '시그모이드 함수'라고도 합니다. 이는 가장 인기 있는 활성화 함수였습니다. '로지스틱 함수 이전의 뉴런 출력' 'logits'로 단축되었습니다.
loss: 신경망 출력을 정답과 비교하는 오류 함수
뉴런: 입력의 가중 합계를 계산하고 편향을 더한 후 활성화 함수를 통해 결과를 제공합니다.
원-핫 인코딩: 클래스 5개 중 3개가 5개 요소로 구성된 벡터로 인코딩됩니다. 이때 세 번째 원-핫 인코딩은 1인 클래스만 제외하고 모두 0입니다.
relu: 정류 선형 유닛입니다. 뉴런에 널리 사용되는 활성화 함수입니다.
시그모이드: 예전에는 널리 사용되어 왔지만 특별한 경우에 여전히 유용한 또 다른 활성화 함수입니다.
소프트맥스: 벡터에서 작동하고, 가장 큰 구성요소와 다른 구성요소 간의 차이를 늘리고, 확률 벡터로 해석될 수 있도록 벡터를 합계가 1이 되도록 정규화합니다. 분류기의 마지막 단계로 사용됩니다.
tensor: '텐서' 는 행렬과 같지만, 임의의 차원 수를 사용합니다. 1차원 텐서는 벡터입니다. 2차원 텐서는 행렬입니다. 그런 다음 3차원, 4차원, 5차원 또는 그 이상의 차원을 가진 텐서를 사용할 수 있습니다.
5. 코드를 살펴보겠습니다.
학습 노트북으로 돌아가서 이번에는 코드를 읽어 보겠습니다.
이 노트북의 모든 셀을 살펴보겠습니다.
셀 '매개변수'
배치 크기, 학습 에포크 수, 데이터 파일의 위치는 여기에 정의되어 있습니다. 데이터 파일은 GCS (Google Cloud Storage) 버킷에 호스팅되므로 주소가 gs://
로 시작합니다.
'가져오기' 셀
TensorFlow와 시각화를 위한 Matplotlib 등 필요한 모든 Python 라이브러리를 여기로 가져옵니다.
셀 "시각화 유틸리티 [RUN ME]****
이 셀에는 흥미로운 시각화 코드가 포함되어 있습니다. 기본적으로 접혀 있지만 시간이 있을 때 더블클릭하여 열어 코드를 볼 수 있습니다.
셀 'tf.data.Dataset: 파일 파싱 및 학습 및 검증 데이터 세트 준비'
이 셀은 tf.data.Dataset API를 사용하여 데이터 파일 형태의 MNIST 데이터 세트를 로드했습니다. 이 셀에 너무 많은 시간을 할애할 필요는 없습니다. tf.data.Dataset API에 관심이 있다면 TPU 속도의 데이터 파이프라인 튜토리얼에서 이에 대해 설명해 드리겠습니다. 현재 기본 설정은 다음과 같습니다.
MNIST 데이터 세트의 이미지와 라벨 (정답)은 4개의 파일로 고정된 길이의 레코드에 저장됩니다. 파일은 전용 고정 레코드 함수를 사용하여 로드할 수 있습니다.
imagedataset = tf.data.FixedLengthRecordDataset(image_filename, 28*28, header_bytes=16)
이제 이미지 바이트의 데이터 세트가 만들어졌습니다. 이미지로 디코딩해야 합니다. 이를 위한 함수를 정의합니다. 이미지는 압축되지 않으므로 함수는 아무것도 디코딩할 필요가 없습니다 (decode_raw
는 기본적으로 아무 작업도 하지 않음). 그런 다음 이미지는 0과 1 사이의 부동 소수점 값으로 변환됩니다. 여기에서 2D 이미지로 모양을 변경할 수 있지만 실제로는 크기가 28*28인 픽셀의 평면 배열로 유지합니다. 이것이 초기 밀집 레이어가 예상하기 때문입니다.
def read_image(tf_bytestring):
image = tf.io.decode_raw(tf_bytestring, tf.uint8)
image = tf.cast(image, tf.float32)/256.0
image = tf.reshape(image, [28*28])
return image
.map
를 사용하여 이 함수를 데이터 세트에 적용하고 이미지의 데이터 세트를 가져옵니다.
imagedataset = imagedataset.map(read_image, num_parallel_calls=16)
라벨에 대해 동일한 종류의 읽기 및 디코딩을 수행하며 이미지와 라벨을 함께 .zip
합니다.
dataset = tf.data.Dataset.zip((imagedataset, labelsdataset))
이제 쌍 (image, label)의 데이터 세트가 있습니다. 이것이 우리가 기대하는 것입니다. 아직 학습 함수에서 사용할 준비가 되지 않았습니다.
dataset = dataset.cache()
dataset = dataset.shuffle(5000, reshuffle_each_iteration=True)
dataset = dataset.repeat()
dataset = dataset.batch(batch_size)
dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE)
tf.data.Dataset API에는 데이터 세트를 준비하는 데 필요한 모든 유틸리티 함수가 있습니다.
.cache
는 RAM에 데이터 세트를 캐시합니다. 이것은 작은 데이터 세트이므로 작동할 것입니다. .shuffle
는 요소 5,000개로 구성된 버퍼로 셔플합니다. 학습 데이터의 셔플이 중요합니다. .repeat
는 데이터 세트를 루프 처리합니다. 여러 번 (여러 세대) 학습하게 됩니다. .batch
는 여러 이미지와 라벨을 미니 배치로 함께 가져옵니다. 마지막으로 .prefetch
는 현재 배치가 GPU에서 학습되는 동안 CPU를 사용하여 다음 배치를 준비할 수 있습니다.
검증 데이터 세트는 비슷한 방식으로 준비됩니다. 이제 모델을 정의하고 이 데이터 세트를 사용하여 모델을 학습시킬 준비가 되었습니다.
셀 'Keras 모델'
모든 모델은 직선 레이어 시퀀스이므로 tf.keras.Sequential
스타일을 사용하여 만들 수 있습니다. 처음에는 하나의 밀집 레이어입니다. 손으로 쓴 숫자를 10개의 클래스로 분류하기 때문에 뉴런이 10개 있습니다. '소프트맥스'를 사용해 활성화해야 합니다.
Keras 모델은 입력의 형태도 알아야 합니다. tf.keras.layers.Input
를 사용하여 정의할 수 있습니다. 여기서 입력 벡터는 길이가 28*28인 픽셀 값의 플랫 벡터입니다.
model = tf.keras.Sequential(
[
tf.keras.layers.Input(shape=(28*28,)),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='sgd',
loss='categorical_crossentropy',
metrics=['accuracy'])
# print model layers
model.summary()
# utility callback that displays training curves
plot_training = PlotTraining(sample_rate=10, zoom=1)
모델 구성은 Keras에서 model.compile
함수를 사용하여 구성합니다. 여기서는 기본 옵티마이저 'sgd'
(확률적 경사하강법)를 사용합니다. 분류 모델에는 Keras에서 'categorical_crossentropy'
이라는 교차 엔트로피 손실 함수가 필요합니다. 마지막으로 올바르게 분류된 이미지의 비율인 'accuracy'
측정항목을 계산하도록 모델에 요청합니다.
Keras는 개발자가 만든 모델의 세부정보를 출력하는 매우 유용한 model.summary()
유틸리티를 제공합니다. Kind 강사가 '시각화 유틸리티' 셀에 정의된 PlotTraining
유틸리티를 추가했습니다. 이 유틸리티는 교육 중에 다양한 학습 곡선을 표시합니다.
'모델 학습 및 검증' 셀
여기서 model.fit
를 호출하고 학습 데이터 세트와 검증 데이터 세트를 모두 전달하여 학습이 이루어집니다. 기본적으로 Keras는 각 에포크가 끝날 때 검증 라운드를 실행합니다.
model.fit(training_dataset, steps_per_epoch=steps_per_epoch, epochs=EPOCHS,
validation_data=validation_dataset, validation_steps=1,
callbacks=[plot_training])
Keras에서는 학습 중에 콜백을 사용하여 커스텀 동작을 추가할 수 있습니다. 이 워크숍에서는 동적으로 업데이트되는 학습 플롯이 이렇게 구현되었습니다.
'예측 시각화' 셀
모델이 학습되면 model.predict()
를 호출하여 예측을 얻을 수 있습니다.
probabilities = model.predict(font_digits, steps=1)
predicted_labels = np.argmax(probabilities, axis=1)
여기서는 테스트용으로 로컬 글꼴에서 렌더링된 인쇄된 숫자 세트를 준비했습니다. 신경망은 최종 '소프트맥스'에서 확률이 10개인 벡터를 반환합니다. 라벨을 얻으려면 어떤 확률이 가장 높은지 알아내야 합니다. NumPy 라이브러리의 np.argmax
가 이 작업을 실행합니다.
axis=1
매개변수가 필요한 이유를 이해하려면 128개의 이미지로 구성된 배치를 처리했으므로 모델이 128개의 확률 벡터를 반환한다는 점을 기억하세요. 출력 텐서의 셰이프는 [128, 10]입니다. 각 이미지에 대해 반환된 10개의 확률에 대한 argmax를 계산하므로 axis=1
(첫 번째 축이 0임)
이 간단한 모델은 이미 숫자의 90% 를 인식합니다. 나쁘지는 않지만 이제 이를 크게 개선할 수 있습니다.
6. 레이어 추가
인식 정확도를 개선하기 위해 신경망에 더 많은 레이어를 추가할 것입니다.
마지막 레이어에서 소프트맥스를 활성화 함수로 유지합니다. 마지막 레이어가 분류에 가장 효과적이기 때문입니다. 그러나 중간 레이어에서는 가장 일반적인 활성화 함수인 시그모이드를 사용할 것입니다.
예를 들어 모델은 다음과 같이 표시될 수 있습니다 (쉼표를 잊지 마세요. tf.keras.Sequential
는 쉼표로 구분된 레이어 목록을 사용합니다).
model = tf.keras.Sequential(
[
tf.keras.layers.Input(shape=(28*28,)),
tf.keras.layers.Dense(200, activation='sigmoid'),
tf.keras.layers.Dense(60, activation='sigmoid'),
tf.keras.layers.Dense(10, activation='softmax')
])
'요약' 보기 살펴보겠습니다 이제 최소 10배 더 많은 매개변수가 있습니다. 10배는 더 좋아질 거야! 그러나 어떤 이유에서는 그렇지 않습니다.
피해도 지붕을 통과한 것으로 보입니다. 문제가 발생했습니다.
7. 심층 네트워크 특별 관리
사람들이 80년대와 90년대에 신경망을 설계할 때 사용하던 신경망을 방금 경험했습니다. 소위 말하는 'AI의 겨울'을 앞두고 이 아이디어를 포기한 것은 당연합니다. 실제로 레이어를 추가할수록 신경망을 수렴하는 데 점점 더 많은 어려움이 발생합니다.
다수의 레이어 (20, 50, 심지어 100개, 오늘날에도 100개)가 있는 심층신경망은 수렴할 수 있는 몇 가지 수학적 트릭을 통해 아주 잘 작동할 수 있다는 것이 밝혀졌습니다. 이러한 단순한 트릭의 발견은 2010년대 딥 러닝의 르네상스 시대를 한 이유 중 하나입니다.
RELU 활성화
시그모이드 활성화 함수는 실제로 심층 네트워크에서 상당히 문제가 됩니다. 0과 1 사이의 모든 값을 밀어내며, 반복적으로 이렇게 하면 뉴런 출력과 경사가 완전히 사라질 수 있습니다. 지금까지 언급했듯이, 최신 네트워크에서는 다음과 같은 RELU (정류 선형 유닛)을 사용합니다.
반면 렐루의 경우 오른쪽에는 1의 도함수가 있습니다. RELU 활성화를 사용하면 일부 뉴런에서 발생하는 경사가 0일 수 있지만 다른 뉴런은 항상 0이 아닌 명확하게 경사를 제공하며 학습이 적절한 속도로 계속될 수 있습니다.
더 나은 옵티마이저
여기처럼 고차원 공간에서는 약 10,000개의 가중치와 편향이 있으며 '새들 포인트'가 있습니다. 자주 발생합니다 국소 최솟값은 아니지만 경사는 여전히 0이고 경사하강법 옵티마이저가 거기에 머물러 있는 점들입니다. TensorFlow에는 상당한 양의 관성을 사용해 안장점을 지날 때 안전하게 항해하는 일부 옵티마이저를 포함하여 다양한 옵티마이저가 제공됩니다.
무작위 초기화
학습 전에 가중치 편향을 초기화하는 기술은 그 자체로 연구 분야로서, 이 주제에 대해 수많은 논문이 발표되었습니다. 여기에서 Keras에서 사용할 수 있는 모든 이니셜라이저를 살펴볼 수 있습니다. 다행히 Keras는 기본적으로 올바른 작업을 실행하며 거의 모든 경우에 가장 적합한 'glorot_uniform'
이니셜라이저를 사용합니다.
Keras가 이미 올바른 작업을 수행했으므로 개발자가 취해야 할 조치는 없습니다.
NaN ???
교차 엔트로피 공식에는 로그가 포함되고 log(0)는 숫자가 아님 (NaN, 원하는 경우 숫자 충돌)입니다. 교차 엔트로피에 대한 입력이 0일 수 있나요? 입력은 기본적으로 지수이고 지수는 0이 아닌 소프트맥스에서 가져옵니다. 그러니까 우리는 안전해!
정말요? 아름다운 수학 세계에서는 안전할 수 있지만 컴퓨터 환경에서는 float32 형식으로 표현되는 exp(-150)가 아무리 낮고 교차 엔트로피가 다운됩니다.
다행히도, Keras가 이 작업을 처리하고 수치 안정성을 보장하고 NaN을 회피하기 위해 특히 세심한 방식으로 소프트맥스와 교차 엔트로피를 계산하기 때문에 여기서 사용자가 할 일은 없습니다.
성공?
이제 97% 의 정확성을 달성할 수 있습니다. 이 워크숍의 목표는 99% 이상을 달성하는 것이므로 계속 분발해 보겠습니다.
문제가 발생하면 현재 해결책은 다음과 같습니다.
8. 학습률 감소
학습을 더 빠르게 해볼 수 있지 않을까? Adam 옵티마이저의 기본 학습률은 0.001입니다. 속도를 높여 보겠습니다.
속도가 빨라도 별다른 도움이 되지 않는 것 같습니다. 이 잡음은 어떤 의미일까요?
학습 곡선은 정말 노이즈가 많고 두 검증 곡선을 보면 오르락내리락하고 있습니다. 이것은 우리가 너무 빨리 가고 있다는 것을 의미합니다. 이전 속도로 돌아갈 수도 있지만 더 좋은 방법이 있습니다.
좋은 해결책은 빠르게 시작한 후 학습률을 기하급수적으로 줄이는 것입니다. Keras에서는 tf.keras.callbacks.LearningRateScheduler
콜백을 사용하여 이 작업을 실행할 수 있습니다.
복사하여 붙여넣기에 유용한 코드:
# lr decay function
def lr_decay(epoch):
return 0.01 * math.pow(0.6, epoch)
# lr schedule callback
lr_decay_callback = tf.keras.callbacks.LearningRateScheduler(lr_decay, verbose=True)
# important to see what you are doing
plot_learning_rate(lr_decay, EPOCHS)
직접 만든 lr_decay_callback
를 사용해야 합니다. 이를 model.fit
의 콜백 목록에 추가합니다.
model.fit(..., callbacks=[plot_training, lr_decay_callback])
이 작은 변화가 일으킨 영향은 엄청납니다. 대부분의 노이즈가 사라졌으며 테스트 정확도는 지속적으로 98% 를 넘습니다.
9. 드롭아웃, 과적합
이제 모델이 원활하게 수렴되고 있는 것 같습니다. 좀 더 깊이 들어가 보겠습니다.
도움이 되었습니까?
그렇지 않습니다. 정확성이 여전히 98% 에서 멈췄으며 검증 손실을 살펴보세요. 점점 높아지고 있어! 학습 알고리즘은 학습 데이터에 대해서만 작동하며 그에 따라 학습 손실을 최적화합니다. 유효성 검사 데이터는 절대 볼 수 없으므로 얼마 후의 작업이 유효성 검사 손실에 더 이상 영향을 미치지 않아 감소가 멈추고 때로는 다시 반사되는 경우도 있습니다.
이는 모델의 실제 인식 능력에 즉시 영향을 미치지는 않지만 여러 번 반복하지 못하게 되며 일반적으로 학습이 더 이상 긍정적인 영향을 미치지 않는다는 신호입니다.
이러한 연결 해제를 일반적으로 '과적합'이라고 합니다. '드롭아웃'이라는 정규화 기술을 적용해 볼 수 있습니다. 드롭아웃 기법은 학습을 반복할 때마다 임의의 뉴런을 발사합니다.
결과
드롭아웃이 작동하는 방식을 감안할 때 당연히 노이즈가 다시 나타납니다. 검증 손실이 더 이상 증가하지 않는 것 같지만 드롭아웃이 없는 것보다 전반적으로 더 높습니다. 검증 정확도가 약간 떨어졌습니다. 이는 상당히 실망스러운 결과입니다.
드롭아웃이 올바른 솔루션이 아니거나 '과적합'인 것 같습니다. 더 복잡한 개념이며 일부 원인은 '드롭아웃'에 적합하지 않습니다. 어떻게 해야 할까요?
'과적합'이란 무엇인가요? 과적합은 신경망이 학습 사례에서는 효과가 있지만 실제 데이터에서는 그렇지 않은 방식으로 '잘못' 학습했을 때 발생합니다. 드롭아웃과 같이 더 나은 방식으로 학습하도록 강제할 수 있는 정규화 기법도 있지만 과적합은 더 깊은 뿌리를 갖고 있습니다.
기본적인 과적합은 신경망이 당면한 문제에 대해 너무 많은 자유도를 가질 때 발생합니다. 뉴런이 너무 많아 네트워크가 모든 학습 이미지를 저장한 다음 패턴 매칭을 통해 인식할 수 있다고 상상해 보세요. 실제 데이터에는 완전히 실패할 것입니다. 신경망은 학습 중에 학습하는 내용을 일반화하도록 어느 정도 제약을 받아야 합니다.
학습 데이터가 극히 적으면 작은 신경망이라도 데이터를 학습할 수 있으므로 '과적합' 현상이 나타납니다. 일반적으로 신경망을 학습시키려면 항상 많은 양의 데이터가 필요합니다.
마지막으로, 책에 제시된 모든 작업을 마쳤고, 자유도를 제한하고, 드롭아웃을 적용하고, 많은 데이터로 학습시켰는지 확인하기 위해 다양한 크기의 네트워크를 실험해 본 경우, 여전히 개선이 불가능해 보이는 성능 수준에 머물게 될 수 있습니다. 이는 현재의 형태인 신경망이 이 경우와 같이 데이터에서 더 많은 정보를 추출할 수 없다는 의미입니다.
단일 벡터로 평면화된 이미지를 사용하는 방법을 기억하시나요? 좋지 않은 생각이네요. 필기 입력 숫자는 도형으로 구성되며 픽셀을 평면화할 때 도형 정보는 삭제했습니다. 그러나 형태 정보를 활용할 수 있는 일종의 신경망인 컨볼루셔널 신경망이 있습니다. 한번 해 보죠.
문제가 발생하면 현재 해결책은 다음과 같습니다.
10. [정보] 컨볼루셔널 신경망
요약
다음 단락에서 굵게 표시된 모든 용어를 이미 알고 있는 경우 다음 실습으로 이동할 수 있습니다. 컨볼루셔널 신경망을 이제 막 배우셨다면 계속 읽어 보시기 바랍니다.
그림: 각각 4x4x3=48의 학습 가능 가중치로 구성된 2개의 연속된 필터로 이미지를 필터링하고 있습니다.
Keras에서 간단한 컨볼루셔널 신경망은 다음과 같습니다.
model = tf.keras.Sequential([
tf.keras.layers.Reshape(input_shape=(28*28,), target_shape=(28, 28, 1)),
tf.keras.layers.Conv2D(kernel_size=3, filters=12, activation='relu'),
tf.keras.layers.Conv2D(kernel_size=6, filters=24, strides=2, activation='relu'),
tf.keras.layers.Conv2D(kernel_size=6, filters=32, strides=2, activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(10, activation='softmax')
])
컨볼루셔널 신경망의 레이어에는 하나의 '뉴런'이 는 이미지의 작은 영역에 대해서만 바로 위에 있는 픽셀의 가중 합계를 수행합니다. 일반 밀집 레이어의 뉴런처럼 편향을 추가하고 활성화 함수를 통해 합계를 제공합니다. 그런 다음 동일한 가중치를 사용하여 전체 이미지에서 이 연산을 반복합니다. 밀집 레이어에서 각 뉴런에는 고유한 가중치가 있다는 점을 기억하세요. 여기에서는 단일 '패치'가 이미지에서 양방향으로 슬라이드되는 가중치의 비율('컨볼루션') 출력에는 이미지의 픽셀 수만큼의 값이 있습니다. 하지만 가장자리에는 일부 패딩이 필요합니다. 이는 필터링 작업입니다. 위 그림에서는 4x4x3=48 가중치 필터를 사용합니다.
하지만 48개의 가중치로는 충분하지 않습니다. 자유도를 더 추가하려면 새로운 가중치 집합으로 동일한 연산을 반복합니다. 그러면 새로운 필터 출력 세트가 생성됩니다. 'channel'이라고 하겠습니다. 출력의 R,G,B 채널을 입력 이미지의 채널과 비유하면 됩니다
새 차원을 추가하여 두 개 이상의 가중치 집합을 하나의 텐서로 합산할 수 있습니다. 이렇게 하면 컨볼루셔널 레이어에 대한 가중치 텐서의 일반적인 형태를 얻을 수 있습니다. 입력 및 출력 채널의 수가 매개변수이므로 컨볼루셔널 레이어를 스택하고 체이닝할 수 있습니다.
삽화: 컨볼루셔널 신경망이 '정육면체'를 변환 데이터를 다른 '정육면체'로 확인할 수 있습니다
스트라이드 컨볼루션, 최대 풀링
2 또는 3의 스트라이드로 컨볼루션을 수행함으로써 결과로 생성되는 데이터 큐브를 수평 차원에서 축소할 수도 있습니다. 여기에는 두 가지 일반적인 방법이 있습니다.
- 스트라이드 컨볼루션: 위와 같지만 스트라이드가 1보다 큰 슬라이딩 필터
- 최대 풀링: MAX 연산을 적용하는 슬라이딩 윈도우 (일반적으로 2x2 패치에서 2픽셀마다 반복됨)
그림: 컴퓨팅 기간을 3픽셀 단위로 슬라이드하면 출력 값이 감소합니다. 스트라이드 컨볼루션 또는 최대 풀링 (2x2 윈도우에서 2의 스트라이드 슬라이딩의 최댓값)는 수평 차원에서 데이터 큐브를 축소하는 방법입니다.
마지막 레이어
마지막 컨볼루셔널 레이어 다음에 오는 데이터는 '정육면체'가 됩니다. 최종 밀집 레이어에 데이터를 공급하는 방법에는 두 가지가 있습니다.
첫 번째 방법은 데이터 큐브를 벡터로 평면화한 다음 소프트맥스 레이어에 공급하는 것입니다. 때로는 소프트맥스 레이어 앞에 밀집 레이어를 추가할 수도 있습니다. 이 경우 가중치 수가 더 많을 수 있습니다. 컨볼루셔널 신경망의 끝에 있는 밀집 레이어는 전체 신경망의 가중치의 절반 이상을 포함할 수 있습니다.
값비싼 밀집 레이어를 사용하는 대신 들어오는 데이터 '큐브'를 분할할 수도 있습니다. 값의 평균을 내며 소프트맥스 활성화 함수를 통해 값을 입력합니다. 이 방식으로 분류 헤드를 빌드하는 방식에는 가중치가 없습니다. Keras에는 이를 위한 레이어 tf.keras.layers.GlobalAveragePooling2D()
가 있습니다.
다음 섹션으로 이동하여 당면한 문제에 대한 컨볼루셔널 신경망을 빌드하세요.
11. 컨볼루셔널 신경망
필기 입력 숫자 인식을 위한 컨볼루셔널 신경망을 빌드해 보겠습니다. 상단에 컨볼루셔널 레이어 3개를 사용하고 하단에 기존의 소프트맥스 판독 레이어를 사용하여 완전히 연결된 레이어 하나와 연결합니다.
두 번째 컨볼루셔널 레이어와 세 번째 컨볼루셔널 레이어는 2의 보폭으로 출력 값의 수를 28x28에서 14x14로 줄인 후 7x7로 줄이는 이유를 설명합니다.
Keras 코드를 작성해 보겠습니다.
첫 번째 컨볼루셔널 레이어 전에 특별한 주의가 필요합니다. 실제로 3D 큐브가 있어야 데이터 세트는 밀집 레이어에 맞게 설정되었고 이미지의 모든 픽셀은 벡터로 평면화되었습니다. 28x28x1 이미지 (그레이 스케일 이미지의 경우 채널 1개)로 모양을 다시 바꿔야 합니다.
tf.keras.layers.Reshape(input_shape=(28*28,), target_shape=(28, 28, 1))
지금까지 사용한 tf.keras.layers.Input
레이어 대신 이 선을 사용할 수 있습니다.
Keras에서 'relu' 활성화 컨볼루셔널 레이어의 문법은 다음과 같습니다.
tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu')
스트라이드 컨볼루션의 경우 다음과 같이 작성합니다.
tf.keras.layers.Conv2D(kernel_size=6, filters=24, padding='same', activation='relu', strides=2)
밀집 레이어가 사용할 수 있도록 데이터 큐브를 벡터로 평면화하는 방법:
tf.keras.layers.Flatten()
밀집 레이어의 경우 구문이 변경되지 않았습니다.
tf.keras.layers.Dense(200, activation='relu')
모델이 99% 정확성 장벽을 허물었나요? 거의 비슷함... 검증 손실 곡선을 살펴보겠습니다. 벨이 울리나요?
예측 결과도 살펴보세요. 처음으로 10,000개의 테스트 숫자 대부분이 올바르게 인식되는 것을 확인할 수 있습니다. 오탐의 약 41⁄2행만 남아 있습니다 (10,000개 중 약 110자리).
문제가 발생하면 현재 해결책은 다음과 같습니다.
12. 다시 드롭아웃
이전 학습에서는 과적합의 명확한 징후가 보이지만 여전히 99% 의 정확성에 미치지 못합니다. 드롭아웃을 다시 시도해 볼까요?
이번에는 어땠나요?
이번에는 드롭아웃이 효과가 있었던 것 같습니다. 검증 손실이 더 이상 증가하지 않으며 최종 정확도는 99%를 넘을 것입니다. 축하합니다.
드롭아웃을 적용하려고 할 때는 과적합 문제가 있다고 생각했는데 실제로는 신경망 아키텍처에 문제가 있었습니다. 컨볼루셔널 레이어가 없으면 더 나아가 드롭아웃이 할 수 있는 일이 없습니다.
이번에는 과적합이 문제의 원인으로 보이며 드롭아웃이 실제로 도움이 되었습니다. 검증 손실이 증가하면서 학습 손실 곡선과 검증 손실 곡선 사이에 단절이 발생할 수 있는 이유는 많습니다. 자유도가 너무 높아 네트워크에서 부적절하게 사용되는 과적합은 그중 하나일 뿐입니다. 데이터 세트가 너무 작거나 신경망 아키텍처가 적절하지 않은 경우 손실 곡선에서 유사한 동작이 나타날 수 있지만 드롭아웃은 도움이 되지 않습니다.
13. 배치 정규화
마지막으로 배치 정규화를 추가해 보겠습니다.
이것이 이론이며, 실제로 몇 가지 규칙을 기억하면 됩니다.
지금은 이 책을 읽으면서 각 신경망 레이어에 배치 norm 레이어를 제외한 마지막 레이어를 추가해 보겠습니다. 마지막 '소프트맥스'에 추가하지 마세요. 레이어가 있습니다 별로 유용하지 않을 것입니다.
# Modify each layer: remove the activation from the layer itself.
# Set use_bias=False since batch norm will play the role of biases.
tf.keras.layers.Conv2D(..., use_bias=False),
# Batch norm goes between the layer and its activation.
# The scale factor can be turned off for Relu activation.
tf.keras.layers.BatchNormalization(scale=False, center=True),
# Finish with the activation.
tf.keras.layers.Activation('relu'),
현재 정확도가 어떻습니까?
약간의 조정 (BATCH_SIZE=64, 학습률 감소 매개변수 0.666, 밀집 레이어에서의 드롭아웃율 0.3)을 조금만 조정하면 99.5%에 도달할 수 있습니다. 학습률 및 드롭아웃 조정이 '권장사항'에 따라 수행되었습니다. 'batch norm'을 사용할 수 있습니다.
- 배치 놈(norm)을 사용하면 신경망을 수렴하는 데 도움이 되며 일반적으로 더 빠르게 학습시킬 수 있습니다.
- 배치 norm은 정규화입니다. 일반적으로 사용하는 드롭아웃의 양을 줄이거나 드롭아웃을 전혀 사용하지 않을 수도 있습니다.
솔루션 노트북의 학습 실행은 99.5% 입니다.
14. 강력한 하드웨어로 클라우드에서 학습: AI Platform
GitHub의 MLengine 폴더에서 클라우드 지원 버전의 코드와 Google Cloud AI Platform에서 코드를 실행하는 방법을 확인할 수 있습니다. 이 단계를 실행하려면 먼저 Google Cloud 계정을 만들고 결제를 사용 설정해야 합니다. 실습을 완료하는 데 필요한 리소스는 2달러 미만입니다 (하나의 GPU에서 학습 시간이 1시간이라고 가정). 계정을 준비하려면 다음 단계를 따르세요.
- Google Cloud Platform 프로젝트 ( http://cloud.google.com/console)를 만듭니다.
- 결제를 사용 설정합니다.
- GCP 명령줄 도구를 설치합니다 ( GCP SDK 여기).
- Google Cloud Storage 버킷 (
us-central1
리전에 배치)을 만듭니다. 학습 코드를 스테이징하고 학습된 모델을 저장하는 데 사용됩니다. - 필요한 API를 사용 설정하고 필요한 할당량을 요청합니다. 학습 명령어를 한 번 실행하면 사용 설정할 항목을 알려주는 오류 메시지가 표시됩니다.
15. 축하합니다.
여러분은 최초의 신경망을 빌드하고 99% 의 정확도까지 학습시켰습니다. 이 과정에서 학습한 기술은 MNIST 데이터 세트에만 국한되지 않으며, 실제로 신경망으로 작업할 때 널리 사용됩니다. 작별 인사로 드리는 '절벽의 노트'입니다. 카드입니다. 배운 내용을 기억하는 데 사용할 수 있습니다.
다음 단계
- 완전히 연결된 컨볼루셔널 신경망을 만든 후에는 순환 신경망을 살펴보아야 합니다.
- 분산 인프라의 클라우드에서 학습 또는 추론을 실행할 수 있도록 Google Cloud는 AI Platform을 제공합니다.
- 마지막으로, YouTube는 고객의 의견을 소중하게 생각합니다. 이 실습에서 부족한 부분이 있거나 개선이 필요하다고 생각되는 부분이 있으면 알려 주세요. YouTube는 GitHub 문제[의견 링크]를 통해 의견을 처리합니다.
작성자: 마틴 괴르너트위터: @martin_gorner |
이 실습의 모든 만화 이미지 저작권: alexpokusay / 123RF 스톡 사진