나님을 위해 향후 잊어먹을경우를 위해 기억을 저장해 둔다.

WIN10에서 아나콘다로 tensorflow를 설치한 경우이다.

본인과 설치 환경이 다를 수 있으므로 안된다고 묻지 마세요.

 

Tensorflow로 MNIST 테스트 하려고 하는데 다음과 같은 오류로 에러가 발생하면서 안될 때 해결 방법을 설명한다.

 

 

input_data라고 하는 녀석을 찾을 수 없다고 하는데...

아나콘다로 설치하면 tensorflow.examples.tutorials 폴더 내 mnist폴더 조차 없다.

아나콘다 환경 설정에서도 설치할 수 없었다.

그래서 나는 수동 설치 했다.

즉, input_data.py 파일을 직접 수동으로 다운로드 해서 tensorflow의 해당 경로에 설치하도록 한다.

 

 

1. input_data.py 파일이 있는 github 소스 페이지로 이동.

   [input_data.py 파일 위치로 바로 가기]

 

2. Raw 파일 버튼을 눌러서 파일 내용을 열람한다.

3. 파일 내용을 복사하고 메모장을 열어 붙여넣기 한 후 input_data.py라는 파일 이름으로 저장한다.

    저장 후 나중에 찾기 쉽도록 "바탕화면"에 저장한다.

 

 

4. 윈도 탐색기를 실행하고 Tensorflow가 설치된 위치로 이동한다.

위 폴더 위치가 바로 아래 코드의 examples 위치이다.

from tensorflow.examples.tutorials.mnist import input_data

tensorflow가 바로 tensorflow_core 폴더와 같다.

나머지 examples는 examples 폴더와 같다.

그렇다면 나머지 tutuorials와 mnist 폴더를 만들고 그 밑에 input_data.py 파일을 집어넣으면 되겠다.

 

 

5. 폴더 만들고 input_data.py 파일 집어넣기.

 

6. 이제 소스 실행하면 문제 없이 실행된다.

 

 

Happy hacking~!

VPN 자동 트리거 기능 추가하기

 

1.  시작 Menu 버튼 클릭 => PowerShell 입력

2. Windows PowerShell 앱에서 오른 마우스 클릭 후 팝업 메뉴 창에서 관리자 권한으로 실행 클릭

3. PowerShell 창에 다음을 입력:

Add-VpnConnectionTriggerApplication-Name CANITPRO –ApplicationID C:\Windows\Notepad.exe

참고: "CANITPRO"라고 된 내용을 이미 설정된 VPN 연결 이름으로 바꾸셔야 합니다. 그리고 앞으로 호출할 ApplicationID에 프로그램 경로도 적어줘야 합니다.

 

4. VPN 자동 트리거 기능을 활성화 하는데 뭐 물어보면 Y 를 입력합니다.  

5. 다음 명령어를 입력함으로 터널링 분리 기능을 활성화 한다.

Set-VpnConnection -Name CANITPRO -SplitTunneling $True

참고: 터널링 분리는 윈도우가 자동 트리거된 VPN을 통해 모든 네트워크 트래픽이 라우팅되는것을 강제로 못하도록 한다. 다만 VPN을 자동 트리거하는 응용프로그램의 데이터만 가능하도록 한다.
 

6. 또한 다음 명령을 입력하여 IDLE(유휴) 연결 해제 시간을 설정하는 것이 좋다.

Set-VpnConnection –Name CANITPRO –IdleDisconnectSeconds 10

참고: 응용 프로그램을 닫은 후 10 초 후에 VPN 연결이 자동으로 끊어진다. 필요에 따라 시간 값을 변경한다.
 

7. 완료되면 다음 명령을 입력하여 자동 트리거가 활성화되었는지 확인한다.

Get-VpnConnection -Name CANITPRO

 

 

 

 

자동 트리거 VPN기능 제거하기
 
다음 명령을 입력하면 초기 설정 응용 프로그램에서 VPN 자동 트리거를 제거 할 수 있다.

Remove-VpnConnectionTriggerApplication -Name CANITPRO –ApplicationID C:\Windows\Notepad.exe

제거 확인을 위해 묻는 창에서 "Y"를 입력하도록 한다.

참고: CANITPRO 라는 글자를 기존에 설정한 VPN 연결 이름으로 꼭 바꿔야 한다. 그리고 호촐할 ApplicationID에 반드시 프로그램 경로를 입력한다.

아래는 Keras에서 다운받은 데이터를 가지고 테스트 해봤음.

import tensorflow.compat.v1 as tf
import numpy as np
tf.disable_v2_behavior()



csv_data = np.loadtxt('D:\Downloads\winequality-red.csv', delimiter=',', dtype=np.float32)
x_data = csv_data[:1000:, 0:-1]
y_data = csv_data[:1000:, [-1]]

#print(x_data.shape, x_data,len(x_data))
#print(y_data.shape, y_data)
print("x_data = ", x_data.shape[0], x_data.shape[1])
print("y_data = ", y_data.shape[0], y_data.shape[1])

NUM_IN = x_data.shape[1]
NUM_OUT = y_data.shape[1]
NUM_CLASS= 10

X = tf.placeholder(tf.float32, shape=[None, NUM_IN])
Y = tf.placeholder(tf.int32, shape=[None, NUM_OUT])
Y_onehot = tf.one_hot(Y, NUM_CLASS)
Y_onehot = tf.reshape(Y_onehot, [-1, NUM_CLASS])
W = tf.Variable(tf.random_normal(shape=[NUM_IN,NUM_CLASS]), name='weight')
B = tf.Variable(tf.random_normal(shape=[NUM_CLASS]), name='bias')

logit = tf.matmul(X, W)+B
H=tf.nn.softmax(logit)
#cost = tf.reduce_mean(-tf.reduce_sum(Y_onehot*tf.log(H), axis=1))
cost_i = tf.nn.softmax_cross_entropy_with_logits(logits=logit, labels=Y_onehot)
cost = tf.reduce_mean(cost_i)
optimizer= tf.train.GradientDescentOptimizer(learning_rate=0.001)
train=optimizer.minimize(cost)


prediction = tf.argmax(H, 1)
correct_prediction = tf.equal(prediction, tf.argmax(Y_onehot,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))


sess = tf.Session()
sess.run(tf.global_variables_initializer())

for step in range(10000):
    sess.run(train, feed_dict={X:x_data, Y:y_data})

loss,ac = sess.run([cost, accuracy], feed_dict={X:x_data, Y:y_data})
print("loss={:.3f}\t accuracy={:.2%}".format(loss, ac))


pred = sess.run(prediction, feed_dict={X:x_data})
for p, y in zip(pred, y_data.flatten()) :
    print( "[{}] P={} Y={}".format( p==int(y), p, int(y)))

 

 

아래는 "모두를 위한 딥러닝" 강좌의 예제.

http://hunkim.github.io/ml/

import tensorflow.compat.v1 as tf
import numpy as np
tf.disable_v2_behavior()



csv_data = np.loadtxt('D:\Downloads\data-03-diabetes.csv', delimiter=',', dtype=np.float32)
x_data = csv_data[:, 0:-1]
y_data = csv_data[:, [-1]]

#print(x_data.shape, x_data,len(x_data))
#print(y_data.shape, y_data)
print("x_data = ", x_data.shape[0], x_data.shape[1])
print("y_data = ", y_data.shape[0], y_data.shape[1])

NUM_IN = x_data.shape[1]
NUM_OUT = y_data.shape[1]

X = tf.placeholder(tf.float32, shape=[None, NUM_IN])
Y = tf.placeholder(tf.float32, shape=[None, NUM_OUT])
W = tf.Variable(tf.random_normal(shape=[NUM_IN,NUM_OUT]), name='weight')
B = tf.Variable(tf.random_normal(shape=[NUM_OUT]), name='bias')

H=tf.sigmoid(tf.matmul(X, W)+B)
cost = -tf.reduce_mean(Y*tf.log(H) + (1-Y)*tf.log(1-H))
optimizer= tf.train.GradientDescentOptimizer(learning_rate=0.001)
train=optimizer.minimize(cost)

predicted = tf.cast(H > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))

sess = tf.Session()
sess.run(tf.global_variables_initializer())

for step in range(20000):
    out_cost, _ = sess.run([cost, train], feed_dict={X:x_data, Y:y_data})
    if step % 200 == 0 :
        print( "step=", step, " cost=", out_cost)

p, a = sess.run([predicted, accuracy], feed_dict={X:x_data, Y:y_data})
print( "predict=", p, "  accuracy=", a)

초등 사칙 복합 연산 문제.xlsm
0.02MB

초등 고학년 혹은 중학교 1학년 아이를 둔 부모에게 유용한 자료일듯 싶다.

간단한 사칙연산은 하지만 혼합된 사칙연산의 경우 계산 순서에 어려움이 있는 경우 많은 실수를 하게 된다.

이런 경우 사칙연산의 계산 순서를 혼동하지 않도록 연습할 수 있는 엑셀 시트를 준비하였다.

필요한 양만큼 인쇄하여 아이들이 수학계산에 어려움을 극복할 수 있기를 도와주기 바란다.

 

정답은 인쇄 후 오려두거나 뒤로 접어서 보이지 않도록 한다.

 

 

버튼을 누르면 2페이지 분량의 문제를 자동으로 생성한다.

 

본 엑셀시트는 내부에 VBA 매크로를 사용하고 있는데 MS 오피스에서 보안 문제로 경고를 하는경우 이를 무시하고 사용하도록 한다.

매크로를 내부에서 사용하므로 보안 경고를 한다. 이를 무시한다.

 

 

 

민물낚시나 바다낚시를 막론하고 물의 맑기를 나타낼 때는 맑다, 깨끗하다, 흐리다, 탁하다는 표현을 사용하는데 특히 배스낚시에서는 물색이 맑은 경우, 영어표현을 그대로 사용하여 클리어 워터(Clear Water)라고 부르기도 한다.

 

그런데 우리가 맑은 물이라고 알고 있는 클리어 워터(Clear Water)의 정의도 배스낚시에서는 여러 가지로 구분이 되고 흐린 물을 뜻하는 표현도 여러 가지가 있다.

 

그러나 정확하게 어느 정도의 맑기를 가진 것을 어떤 표현으로 부른다고 정해진 것은 없는데 뉘앙스에서 차이가 나기 때문에 미국의 배스낚시 정보를 볼 때는 알아두는 것도 나쁘지는 않을 것 같다.

 

그리고 글의 마지막에서는 미국의 프로 배서들이 물의 맑기를 측정하는 방법과 그에 따라서 배스들의 위치를 판단하는 방법을 소개한다.

 

 클리어 워터(Clear Water)

클리어 워터는 일반적으로 4가지로 구분하여 표현하는데 가장 기본적인 클리어 워터(Clear Water)는 맑은 물 중에서는 가장 등급이 낮은 것을 말한다고 보면 되며 맑은 물의 표현은 아래와 같다.

 

- 진 클리어 워터(Gin Clear Water)

(Gin)은 무색투명한 증류주인데 그만큼 깨끗하다는 뜻을 가지고 있으며 맑은 물을 표현할 때는 최고의 등급에 해당한다.

 

- 울트라 클리어 워터(Ultra Clear Water)

그 다음으로 매우 맑은 물을 나타낼 때는 울트라 클리어 워터(Ultra Clear Water)라는 표현을 쓴다.

 

- 크리스탈 클리어 워터(Crystal Clear Water)

말 그대로 수정같이 맑은 물을 뜻한다.

 

 

 

- 클리어 워터(Clear Water)

일반적으로 사용하는 맑은 물이란 표현인데 위의 4가지 표현들은 정확하게 구분을 할 수는 없으나 대단히 맑다는 것을 강조할 때는 클리어 워터(Clear Water)가 아닌 진 클리어 워터(Gin Clear Water), 울트라 클리어 워터(Ultra Clear Water), 크리스탈 클리어 워터(Crystal Clear Water)란 표현을 쓴다는 것을 알아두자.

 

 흐린 물

물색이 흐리거나 탁할 때에도 영어는 다양한 표현을 사용하는데 배스낚시에서는 어떤 표현들을 쓰는지 알아보자.

 

- 스테인드 워터(Stained Water)

스테인드(stained)란 영어단어는 얼룩이 진, 또는 얼룩투성이인 상태를 말하는데 가장 대표적인 것이 홍차를 우려낼 때 탄닌 성분이 많을수록 검게 변하는 것처럼 근처에 소나무 등의 침엽수가 많으면 탄닌으로 인해 물색이 탁해지는 경우가 바로 스테인드 워터(Stained Water)에 해당한다고 할 수 있다.

 

그러나 이 표현은 물의 맑기를 나타낸다기보다는 물색을 나타내는 것이며 물색이 진하거나 푸르스름하다고 해서 흐린 물이란 것은 아니므로 엄밀하게는 스테인드 워터(Stained Water)란 표현도 클리어 워터(Clear Water)에 해당한다고 할 수 있겠으나 그 경계가 모호한 표현이어서 흐린 물에 포함을 시켰다.

 

 

 

- 머키 워터(Murky Water)

영어사전을 검색하면 흐린 물이라고 나오는 머키 워터(Murky Water)는 배스낚시에서는 시야가 조금 나쁜 정도의 흐린 상태를 말할 때 사용한다.

 

 

 

- 머디 워터(Muddy Water)

우리말로 표현하자면 진흙탕물이라고 할 수 있는 상태를 말한다.

 

 

 

- 더티 워터(Dirty Water)

물이 가장 탁한 상태를 표현하는 것으로 배스낚시에서는 수질이 오염된 물을 뜻하는 것이 아니라 물의 대류현상으로 인한 턴오버(Turnover)나 여름철 태풍이 통과할 때 일시적으로 탁한 상태가 될 때를 주로 가리킨다.

 

 물의 맑기(탁도)를 측정하는 방법

물론 이것은 절대적인 것은 아니다. 그러나 토너먼트에 참가하는 프로들에게는 아주 중요한 사항으로 일반적으로 밝은 색상의 루어를 연결하고 릴을 감아 초릿대 부근에 최대한 가까이 오도록 한 다음, 로드를 물속에 넣어 루어가 보이지 않는 지점을 표시하여 판단하는 방법을 사용한다.

 

 물의 맑기에 따른 배스들의 위치를 판단하는 기준

토너먼트에 참가하는 프로들은 상기의 방법으로 물의 맑기를 측정한 다음 배스들이 있는 위치를 대략적으로 아래의 기준에 따라 판단하고 공략을 한다.

 

- 루어가 수중 15 이상에서 보이지 않는다면 배스는 대략 1.8m 이하에 있다고 판단한다.

- 루어가 수중 15~30에서 보이지 않는다면 배스는 대략 3m 이하에 있다고 판단한다.

- 루어가 수중 30~60에서 보이지 않는다면 배스는 대략 4.5m 이하에 있다고 판단한다.

- 루어가 수중 60~1.8m에서 보이지 않는다면 배스는 대략 10m 이하에 있다고 판단한다.

- 루어가 수중 1.8m 이상에서 보이지 않는다면 배스는 대략 17m 이하에 있다고 판단한다.

 

 

1. 수초가없고 / 바닥이 부드러운 지형
상층 : 작은 저크베이트
중층 : 인 라인 스피너
바닥 : 다운샷

2. 수초가없고 / 바닥이 딱딱한 지형
상층 : 작은 저크베이트
중층 : 컬리테일그럽(그럽웜 종류)
바닥 : 쉐이키 헤드리그

 

3. 풀, 연잎 /바닥이 부드러운 지형
상층 : 소프트 저크베이트
중층 : 스윔베이트
바닥 : 텍사스리그

4. 풀, 연잎 / 바닥이 딱딱한 지형
상층 : 소프트 저크베이트
중층 : 스윔베이트
바닥 : 헤비지그(러버지그, 무거운 지그헤드...)

5. 수초, 갈대 / 바닥이 부드러운 지형
상층 : 버즈베이트
중층 : 스윔지그
바닥 : 다운샷

6.수초, 갈대 / 바닥이 딱딱한 지형
상층 : 웨이크베이트

중층 : 스윔지그
바닥 : 스몰지그(마이크로 러버지그, 가벼운 지그헤드...)

 

 

 

 

 

 

 

 

1. 수초가없고 / 바닥이 부드러운 지형
상층 : 포퍼
중층 : 스피너베이트
바닥 : 텍사스리그(웜:벌레)

2. 수초가없고 / 바닥이 딱딱한 지형
상층 : 포퍼
중층 : 스피너베이트
바닥 : 크랭크베이트

3. 풀, 연잎 /바닥이 부드러운 지형
상층 : (할로우) 프로그
중층 : 스윔지그
바닥 : 텍사스리그(크리쳐:생물)

4. 풀, 연잎 / 바닥이 딱딱한 지형
상층 : (할로우) 프로그
중층 : 스윔지그
바닥 : 텍사스리그(비버)

5. 수초, 갈대 / 바닥이 부드러운 지형
상층 : 스윔베이트(노싱커)
중층 : 스피너베이트
바닥 : 텍사스리그(리자드)

6.수초, 갈대 / 바닥이 딱딱한 지형
상층 : 스윔베이트(노싱커)
중층: 스피너베이트
바닥 : 크랭크베이트

 

 

 

 

 

 

1. 수초가없고 / 바닥이 부드러운 지형
상층 : 처거(탑워터종류)
중층 : 채터베이트
바닥 : 텍사스리그(크리처:생물)

2. 수초가없고 / 바닥이 딱딱한 지형
상층 : 처거(탑워터종류)
중층 : 채터베이트
바닥 : 크랭크베이트

3. 풀, 연잎 /바닥이 부드러운 지형
상층 : 버징(toad: 두꺼비)
중층 : 블레이드 스윔베이트
바닥 : 텍사스리그(크리쳐:생물)

4. 풀, 연잎 / 바닥이 딱딱한 지형
상층 : 버징(toad: 두꺼비)
중층 : 블레이드 스윔베이트
바닥 : 텍사스리그(비버)

5. 수초, 갈대 / 바닥이 부드러운 지형
상층 : 프롭베이트
중층 : 콜로라도 - 블레이드 스피너베이트
바닥 : 센코 노싱커

6.수초, 갈대 / 바닥이 딱딱한 지형
상층 : 프롭베이트
중층: 콜로라도 - 블레이드 스피너베이트
바닥 : 크랭크베이트

 

출처 : https://cafe.naver.com/kbass/101227

도구 > 옵션 > Nuget 패키지 관리자 > 패키지 소스

또는

도구 > Nuget 패키지 관리자 > 패키지 관리자 설정 > 패키지 소스

 

 

1. Nuget V2

   추가 URL : https://www.nuget.org/api/v2/

 

2. Nuget V3

   추가 URL : https://api.nuget.org/v3/index.json



 

 

 

기존 코드를 TensorFlow 2.0으로 바꾸기

 

여전히 텐서플로 1.X 버전의 코드를 수정하지 않고 텐서플로 2.0에서 실행할 수 있습니다(contrib 모듈은 제외):

 

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

 

하지만 이렇게 하면 텐서플로 2.0에서 제공하는 많은 장점을 활용할 수 없습니다. 이 문서는 성능을 높이면서 코드는 더 간단하고 유지보수하기 쉽도록 업그레이드하는 방법을 안내합니다.

 

자동 변환 스크립트

첫 번째 단계는 업그레이드 스크립트를 사용해 보는 것입니다.

이는 텐서플로 2.0으로 업그레이드하기 위해 처음에 할 일입니다. 하지만 이 작업이 기존 코드를 텐서플로 2.0 스타일로 바꾸어 주지는 못합니다. 여전히 플레이스홀더(placeholder)나 세션(session), 컬렉션(collection), 그외 1.x 스타일의 기능을 사용하기 위해 tf.compat.v1 아래의 모듈을 참조하고 있을 것입니다.

 

 

 

2.0에 맞도록 코드 수정하기

 

텐서플로 1.x 코드를 텐서플로 2.0으로 변환하는 몇 가지 예를 소개하겠습니다. 이 작업을 통해 성능을 최적화하고 간소화된 API의 이점을 사용할 수 있습니다.

각각의 경우에 수정하는 패턴은 다음과 같습니다:

 

1. tf.Session.run 호출을 바꾸세요.

모든 tf.Session.run 호출을 파이썬 함수로 바꾸어야 합니다.

  • feed_dict와 tf.placeholder는 함수의 매개변수가 됩니다.
  • fetches는 함수의 반환값이 됩니다.

표준 파이썬 디버거 pdb를 사용하여 함수의 코드를 라인 단위로 실행하고 디버깅할 수 있습니다.

작동 결과에 만족하면 그래프 모드에서 효율적으로 실행할 수 있도록 tf.function 데코레이터를 추가합니다. 조금 더 자세한 내용은 오토그래프 가이드를 참고하세요.

2. 파이썬 객체를 사용하여 변수와 손실을 관리하세요.

tf.get_variable 대신에 tf.Variable을 사용하세요.

모든 variable_scope는 파이썬 객체로 바꿀 수 있습니다. 일반적으로 다음 중 하나가 될 것입니다:

  • tf.keras.layers.Layer
  • tf.keras.Model
  • tf.Module

만약 (tf.Graph.get_collection(tf.GraphKeys.VARIABLES)처럼) 변수의 리스트가 필요하다면 Layer와 Model 객체의 .variables이나 .trainable_variables 속성을 사용하세요.

Layer와 Model 클래스는 전역 컬렉션이 필요하지 않도록 몇 가지 다른 속성들도 제공합니다. .losses 속성은 tf.GraphKeys.LOSSES 컬렉션 대신 사용할 수 있습니다.

자세한 내용은 케라스 가이드를 참고하세요.

경고: tf.compat.v1의 상당수 기능은 암묵적으로 전역 컬렉션을 사용합니다.

3. 훈련 루프를 업그레이드하세요.

풀려는 문제에 맞는 고수준 API를 사용하세요. 훈련 루프(loop)를 직접 만드는 것보다 tf.keras.Model.fit 메서드를 사용하는 것이 좋습니다.

고수준 함수는 훈련 루프를 직접 만들 때 놓치기 쉬운 여러 가지 저수준의 세부 사항들을 관리해 줍니다. 예를 들어 자동으로 규제(regularization) 손실을 수집하거나 모델을 호출할 때 training=True로 매개변수를 설정해 줍니다.

4. 데이터 입력 파이프라인을 업그레이드하세요.

데이터 입력을 위해 tf.data 데이터셋을 사용하세요. 이 객체는 효율적이고 간결하며 텐서플로와 잘 통합됩니다.

tf.keras.Model.fit 메서드에 바로 전달할 수 있습니다.

model.fit(dataset, epochs=5)

파이썬에서 직접 반복시킬 수 있습니다:

for example_batch, label_batch in dataset: break

모델 변환하기

준비

In [0]:

from __future__ import absolute_import, division, print_function, unicode_literals
try:
  # Colab only
  %tensorflow_version 2.x
except Exception:
    pass
import tensorflow as tf


import tensorflow_datasets as tfds

저수준 변수와 연산 실행

저수준 API를 사용하는 예는 다음과 같습니다:

  • 재사용을 위해 변수 범위(variable scopes)를 사용하기
  • tf.get_variable로 변수를 만들기
  • 명시적으로 컬렉션을 참조하기
  • 다음과 같은 메서드를 사용하여 암묵적으로 컬렉션을 참조하기:

    • tf.global_variables
    • tf.losses.get_regularization_loss
  • 그래프 입력을 위해 tf.placeholder를 사용하기

  • session.run으로 그래프를 실행하기
  • 변수를 수동으로 초기화하기

변환 전

다음 코드는 텐서플로 1.x를 사용한 코드에서 볼 수 있는 패턴입니다.

in_a = tf.placeholder(dtype=tf.float32, shape=(2))
in_b = tf.placeholder(dtype=tf.float32, shape=(2))

def forward(x):
  with tf.variable_scope("matmul", reuse=tf.AUTO_REUSE):
    W = tf.get_variable("W", initializer=tf.ones(shape=(2,2)),
                        regularizer=tf.contrib.layers.l2_regularizer(0.04))
    b = tf.get_variable("b", initializer=tf.zeros(shape=(2)))
    return W * x + b

out_a = forward(in_a)
out_b = forward(in_b)

reg_loss = tf.losses.get_regularization_loss(scope="matmul")

with tf.Session() as sess:
  sess.run(tf.global_variables_initializer())
  outs = sess.run([out_a, out_b, reg_loss],
                  feed_dict={in_a: [1, 0], in_b: [0, 1]})

변환 후

변환된 코드의 패턴은 다음과 같습니다:

  • 변수는 파이썬 지역 객체입니다.
  • forward 함수는 여전히 필요한 계산을 정의합니다.
  • sess.run 호출은 forward 함수를 호출하는 것으로 바뀝니다.
  • tf.function 데코레이터는 선택 사항으로 성능을 위해 추가할 수 있습니다.
  • 어떤 전역 컬렉션도 참조하지 않고 규제를 직접 계산합니다.
  • 세션이나 플레이스홀더를 사용하지 않습니다.

In [0]:

W = tf.Variable(tf.ones(shape=(2,2)), name="W")
b = tf.Variable(tf.zeros(shape=(2)), name="b")

@tf.function
def forward(x):
  return W * x + b

out_a = forward([1,0])
print(out_a)

In [0]:

out_b = forward([0,1])

regularizer = tf.keras.regularizers.l2(0.04)
reg_loss = regularizer(W)

tf.layers 기반의 모델

tf.layers 모듈은 변수를 정의하고 재사용하기 위해 tf.variable_scope에 의존하는 층 함수를 포함합니다.

변환 전

def model(x, training, scope='model'):
  with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
    x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu,
          kernel_regularizer=tf.contrib.layers.l2_regularizer(0.04))
    x = tf.layers.max_pooling2d(x, (2, 2), 1)
    x = tf.layers.flatten(x)
    x = tf.layers.dropout(x, 0.1, training=training)
    x = tf.layers.dense(x, 64, activation=tf.nn.relu)
    x = tf.layers.batch_normalization(x, training=training)
    x = tf.layers.dense(x, 10, activation=tf.nn.softmax)
    return x

train_out = model(train_data, training=True)
test_out = model(test_data, training=False)

변환 후

  • 층을 단순하게 쌓을 경우엔 tf.keras.Sequential이 적합합니다. (복잡한 모델인 경우 맞춤형 층과 모델이나 함수형 API를 참고하세요.)
  • 모델이 변수와 규제 손실을 관리합니다.
  • tf.layers에서 tf.keras.layers로 바로 매핑되기 때문에 일대일로 변환됩니다.

대부분 매개변수는 동일합니다. 다른 부분은 다음과 같습니다:

  • 모델이 실행될 때 각 층에 training 매개변수가 전달됩니다.
  • 원래 model 함수의 첫 번째 매개변수(입력 x)는 사라집니다. 층 객체가 모델 구축과 모델 호출을 구분하기 때문입니다.

추가 노트:

  • tf.contrib에서 규제를 초기화했다면 다른 것보다 매개변수 변화가 많습니다.
  • 더 이상 컬렉션을 사용하지 않기 때문에 tf.losses.get_regularization_loss와 같은 함수는 값을 반환하지 않습니다. 이는 훈련 루프를 망가뜨릴 수 있습니다.

In [0]:

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.04),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10, activation='softmax')
])

train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 1))

In [0]:

train_out = model(train_data, training=True)
print(train_out)

In [0]:

test_out = model(test_data, training=False)
print(test_out)

In [0]:

# 훈련되는 전체 변수
len(model.trainable_variables)

In [0]:

# 규제 손실
model.losses

변수와 tf.layers의 혼용

기존 코드는 종종 저수준 TF 1.x 변수와 고수준 tf.layers 연산을 혼용합니다.

변경 전

def model(x, training, scope='model'):
  with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
    W = tf.get_variable(
      "W", dtype=tf.float32,
      initializer=tf.ones(shape=x.shape),
      regularizer=tf.contrib.layers.l2_regularizer(0.04),
      trainable=True)
    if training:
      x = x + W
    else:
      x = x + W * 0.5
    x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu)
    x = tf.layers.max_pooling2d(x, (2, 2), 1)
    x = tf.layers.flatten(x)
    return x

train_out = model(train_data, training=True)
test_out = model(test_data, training=False)

변경 후

이런 코드를 변환하려면 이전 예제처럼 층별로 매핑하는 패턴을 사용하세요.

tf.variable_scope는 기본적으로 하나의 층입니다. 따라서 tf.keras.layers.Layer로 재작성합니다. 자세한 내용은 이 문서를 참고하세요.

일반적인 패턴은 다음과 같습니다:

  • __init__에서 층에 필요한 매개변수를 입력 받습니다.
  • build 메서드에서 변수를 만듭니다.
  • call 메서드에서 연산을 실행하고 결과를 반환합니다.

In [0]:

# 모델에 추가하기 위해 맞춤형 층을 만듭니다.
class CustomLayer(tf.keras.layers.Layer):
  def __init__(self, *args, **kwargs):
    super(CustomLayer, self).__init__(*args, **kwargs)

  def build(self, input_shape):
    self.w = self.add_weight(
        shape=input_shape[1:],
        dtype=tf.float32,
        initializer=tf.keras.initializers.ones(),
        regularizer=tf.keras.regularizers.l2(0.02),
        trainable=True)

  # call 메서드가 그래프 모드에서 사용되면
  # training 변수는 텐서가 됩니다.
  @tf.function
  def call(self, inputs, training=None):
    if training:
      return inputs + self.w
    else:
      return inputs + self.w * 0.5

In [0]:

custom_layer = CustomLayer()
print(custom_layer([1]).numpy())
print(custom_layer([1], training=True).numpy())

In [0]:

train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 1))

# 맞춤형 층을 포함한 모델을 만듭니다.
model = tf.keras.Sequential([
    CustomLayer(input_shape=(28, 28, 1)),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
])

train_out = model(train_data, training=True)
test_out = model(test_data, training=False)

노트:

  • 클래스 상속으로 만든 케라스 모델과 층은 v1 그래프(연산간의 의존성이 자동으로 제어되지 않습니다)와 즉시 실행 모드 양쪽에서 실행될 수 있어야 합니다.

    • 오토그래프(autograph)와 의존성 자동 제어(automatic control dependency)를 위해 tf.function()으로 call() 메서드를 감쌉니다.
  • call 메서드에 training 매개변수를 추가하는 것을 잊지 마세요.

    • 경우에 따라 이 값은 tf.Tensor가 됩니다.
    • 경우에 따라 이 값은 파이썬 불리언(boolean)이 됩니다.
  • self.add_weight()를 사용하여 생성자 메서드나 def build() 메서드에서 모델 변수를 만듭니다.

    • build 메서드에서 입력 크기를 참조할 수 있으므로 적절한 크기의 가중치를 만들 수 있습니다.
    • tf.keras.layers.Layer.add_weight를 사용하면 케라스가 변수와 규제 손실을 관리할 수 있습니다.
  • 맞춤형 층 안에 tf.Tensors 객체를 포함하지 마세요.

    • tf.function이나 즉시 실행 모드에서 모두 텐서가 만들어지지만 이 텐서들의 동작 방식은 다릅니다.
    • 상태를 저장하기 위해서는 tf.Variable을 사용하세요. 변수는 양쪽 방식에 모두 사용할 수 있습니다.
    • tf.Tensors는 중간 값을 저장하기 위한 용도로만 사용합니다.

Slim & contrib.layers를 위한 노트

예전 텐서플로 1.x 코드는 Slim 라이브러리를 많이 사용합니다. 이 라이브러리는 텐서플로 1.x의 tf.contrib.layers로 패키지되어 있습니다. contrib 모듈은 더 이상 텐서플로 2.0에서 지원하지 않고 tf.compat.v1에도 포함되지 않습니다. Slim을 사용한 코드를 TF 2.0으로 변환하는 것은 tf.layers를 사용한 코드를 변경하는 것보다 더 어렵습니다. 사실 Slim 코드는 tf.layers로 먼저 변환하고 그 다음 케라스로 변환하는 것이 좋습니다.

  • arg_scopes를 삭제하세요. 모든 매개변수는 명시적으로 설정되어야 합니다.
  • normalizer_fn과 activation_fn를 사용해야 한다면 분리하여 각각 하나의 층으로 만드세요.
  • 분리 합성곱(separable conv) 층은 한 개 이상의 다른 케라스 층으로 매핑합니다(깊이별(depthwise), 점별(pointwise), 분리(separable) 케라스 층).
  • Slim과 tf.layers는 매개변수 이름과 기본값이 다릅니다.
  • 일부 매개변수는 다른 스케일(scale)을 가집니다.
  • 사전 훈련된 Slim 모델을 사용한다면 tf.keras.applications나 TFHub를 확인해 보세요.

일부 tf.contrib 층은 텐서플로 내부에 포함되지 못했지만 TF 애드온(add-on) 패키지로 옮겨졌습니다.

훈련

여러 가지 방법으로 tf.keras 모델에 데이터를 주입할 수 있습니다. 파이썬 제너레이터(generator)와 넘파이 배열을 입력으로 사용할 수 있습니다.

tf.data 패키지를 사용하여 모델에 데이터를 주입하는 것이 권장되는 방법입니다. 이 패키지는 데이터 조작을 위한 고성능 클래스들을 포함하고 있습니다.

tf.queue는 데이터 구조로만 지원되고 입력 파이프라인으로는 지원되지 않습니다.

데이터셋 사용하기

텐서플로 데이터셋(Datasets) 패키지(tfds)는 tf.data.Dataset 객체로 정의된 데이터셋을 적재하기 위한 유틸리티가 포함되어 있습니다.

예를 들어 tfds를 사용하여 MNIST 데이터셋을 적재하는 코드는 다음과 같습니다:

In [0]:

datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)
mnist_train, mnist_test = datasets['train'], datasets['test']

그 다음 훈련용 데이터를 준비합니다:

  • 각 이미지의 스케일을 조정합니다.
  • 샘플의 순서를 섞습니다.
  • 이미지와 레이블(label)의 배치를 만듭니다.

In [0]:

BUFFER_SIZE = 10 # 실전 코드에서는 더 큰 값을 사용합니다.
BATCH_SIZE = 64
NUM_EPOCHS = 5


def scale(image, label):
  image = tf.cast(image, tf.float32)
  image /= 255

  return image, label

train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
test_data = mnist_test.map(scale).batch(BATCH_SIZE)

간단한 예제를 위해 5개의 배치만 반환하도록 데이터셋을 자릅니다:

In [0]:

STEPS_PER_EPOCH = 5

train_data = train_data.take(STEPS_PER_EPOCH)
test_data = test_data.take(STEPS_PER_EPOCH)

In [0]:

image_batch, label_batch = next(iter(train_data))

케라스 훈련 루프 사용하기

훈련 과정을 세부적으로 제어할 필요가 없다면 케라스의 내장 메서드인 fit, evaluate, predict를 사용하는 것이 좋습니다. 이 메서드들은 모델 구현(Sequential, 함수형 API, 클래스 상속)에 상관없이 일관된 훈련 인터페이스를 제공합니다.

이 메서드들의 장점은 다음과 같습니다:

  • 넘파이 배열, 파이썬 제너레이터, tf.data.Datasets을 사용할 수 있습니다.
  • 자동으로 규제와 활성화 손실을 적용합니다.
  • 다중 장치 훈련을 위해 tf.distribute을 지원합니다.
  • 임의의 호출 가능한 객체를 손실과 측정 지표로 사용할 수 있습니다.
  • tf.keras.callbacks.TensorBoard와 같은 콜백(callback)이나 맞춤형 콜백을 지원합니다.
  • 자동으로 텐서플로 그래프를 사용하므로 성능이 뛰어납니다.

Dataset을 사용하여 모델을 훈련하는 예제는 다음과 같습니다. (자세한 작동 방식은 튜토리얼을 참고하세요.)

In [0]:

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.02),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10, activation='softmax')
])

# 맞춤형 층이 없는 모델입니다.
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(train_data, epochs=NUM_EPOCHS)
loss, acc = model.evaluate(test_data)

print("손실 {}, 정확도 {}".format(loss, acc))

맞춤형 훈련 루프 만들기

케라스 모델의 훈련 스텝(step)이 좋지만 그 외 다른 것을 더 제어하려면 자신만의 데이터 반복 루프를 만들고 tf.keras.model.train_on_batch 메서드를 사용해 보세요.

기억할 점: 많은 것을 tf.keras.Callback으로 구현할 수 있습니다.

이 메서드는 앞에서 언급한 메서드의 장점을 많이 가지고 있고 사용자가 바깥쪽 루프를 제어할 수 있습니다.

훈련하는 동안 성능을 확인하기 위해 tf.keras.model.test_on_batch나 tf.keras.Model.evaluate 메서드를 사용할 수도 있습니다.

노트: train_on_batch와 test_on_batch는 기본적으로 하나의 배치에 대한 손실과 측정값을 반환합니다. reset_metrics=False를 전달하면 누적된 측정값을 반환합니다. 이 때는 누적된 측정값을 적절하게 초기화해 주어야 합니다. AUC와 같은 일부 지표는 reset_metrics=False를 설정해야 올바르게 계산됩니다.

앞의 모델을 계속 사용합니다:

In [0]:

# 맞춤형 층이 없는 모델입니다.
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

metrics_names = model.metrics_names

for epoch in range(NUM_EPOCHS):
  # 누적된 측정값을 초기화합니다.
  model.reset_metrics()

  for image_batch, label_batch in train_data:
    result = model.train_on_batch(image_batch, label_batch)
    print("훈련: ",
          "{}: {:.3f}".format(metrics_names[0], result[0]),
          "{}: {:.3f}".format(metrics_names[1], result[1]))
  for image_batch, label_batch in test_data:
    result = model.test_on_batch(image_batch, label_batch,
                                 # return accumulated metrics
                                 reset_metrics=False)
  print("\n평가: ",
        "{}: {:.3f}".format(metrics_names[0], result[0]),
        "{}: {:.3f}".format(metrics_names[1], result[1]))

 

훈련 단계 커스터마이징

자유도를 높이고 제어를 더 하려면 다음 세 단계를 사용해 자신만의 훈련 루프를 구현할 수 있습니다:

  1. 샘플 배치를 만드는 파이썬 제너레이터나 tf.data.Dataset을 반복합니다.
  2. tf.GradientTape을 사용하여 그래디언트를 계산합니다.
  3. tf.keras.optimizer를 사용하여 모델의 가중치 변수를 업데이트합니다.

기억할 점:

  • 클래스 상속으로 만든 층과 모델의 call 메서드에는 항상 training 매개변수를 포함하세요.
  • 모델을 호출할 때 training 매개변수를 올바르게 지정했는지 확인하세요.
  • 사용 방식에 따라 배치 데이터에서 모델이 실행될 때까지 모델 변수가 생성되지 않을 수 있습니다.
  • 모델의 규제 손실 같은 것들을 직접 관리해야 합니다.

v1에 비해 단순해진 것:

  • 따로 변수를 초기화할 필요가 없습니다. 변수는 생성될 때 초기화됩니다.
  • 의존성을 수동으로 제어할 필요가 없습니다. tf.function 안에서도 연산은 즉시 실행 모드처럼 실행됩니다.

In [0]:

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.02),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10, activation='softmax')
])

optimizer = tf.keras.optimizers.Adam(0.001)
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()

@tf.function
def train_step(inputs, labels):
  with tf.GradientTape() as tape:
    predictions = model(inputs, training=True)
    regularization_loss = tf.math.add_n(model.losses)
    pred_loss = loss_fn(labels, predictions)
    total_loss = pred_loss + regularization_loss

  gradients = tape.gradient(total_loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))

for epoch in range(NUM_EPOCHS):
  for inputs, labels in train_data:
    train_step(inputs, labels)
  print("마지막 에포크", epoch)

새로운 스타일의 측정 지표

텐서플로 2.0에서 측정 지표는 객체입니다. 이 객체는 즉시 실행 모드와 tf.function에서 모두 사용할 수 있습니다. 측정 객체는 다음과 같은 메서드를 가집니다:

  • update_state() — 새로운 측정값을 추가합니다.
  • result() — 누적된 측정 결과를 얻습니다.
  • reset_states() — 모든 측정 내용을 지웁니다.

이 객체는 호출 가능합니다. update_state 메서드처럼 새로운 측정값과 함께 호출하면 상태를 업데이트하고 새로운 측정 결과를 반환합니다.

측정 변수를 수동으로 초기화할 필요가 없습니다. 텐서플로 2.0은 자동으로 의존성을 관리하기 때문에 어떤 경우에도 신경 쓸 필요가 없습니다.

다음은 측정 객체를 사용하여 맞춤형 훈련 루프 안에서 평균 손실을 관리하는 코드입니다.

In [0]:

# 측정 객체를 만듭니다.
loss_metric = tf.keras.metrics.Mean(name='train_loss')
accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')

@tf.function
def train_step(inputs, labels):
  with tf.GradientTape() as tape:
    predictions = model(inputs, training=True)
    regularization_loss = tf.math.add_n(model.losses)
    pred_loss = loss_fn(labels, predictions)
    total_loss = pred_loss + regularization_loss

  gradients = tape.gradient(total_loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  # 측정값을 업데이트합니다.
  loss_metric.update_state(total_loss)
  accuracy_metric.update_state(labels, predictions)


for epoch in range(NUM_EPOCHS):
  # 측정값을 초기화합니다.
  loss_metric.reset_states()
  accuracy_metric.reset_states()

  for inputs, labels in train_data:
    train_step(inputs, labels)
  # 측정 결과를 얻습니다.
  mean_loss = loss_metric.result()
  mean_accuracy = accuracy_metric.result()

  print('에포크: ', epoch)
  print('  손실:     {:.3f}'.format(mean_loss))
  print('  정확도: {:.3f}'.format(mean_accuracy))

저장과 복원

체크포인트 호환성

텐서플로 2.0은 객체 기반의 체크포인트를 사용합니다.

이전 이름 기반 스타일의 체크포인트도 여전히 복원할 수 있지만 주의가 필요합니다. 코드 변환 과정 때문에 변수 이름이 바뀔 수 있지만 해결 방법이 있습니다.

가장 간단한 방법은 새로운 모델의 이름과 체크포인트에 있는 이름을 나열해 보는 것입니다:

  • 여전히 모든 변수는 설정 가능한 name 매개변수를 가집니다.
  • 케라스 모델도 name 매개변수를 가집니다. 이 값은 변수 이름의 접두어로 사용됩니다.
  • tf.name_scope 함수를 변수 이름의 접두어를 지정하는데 사용할 수 있습니다. 이 함수는 tf.variable_scope와는 매우 다릅니다. 이름에만 영향을 미치며 변수를 추적하거나 재사용을 관장하지 않습니다.

이것이 주어진 상황에 잘 맞지 않는다면 tf.compat.v1.train.init_from_checkpoint 함수를 시도해 보세요. 이 함수는 assignment_map 매개변수로 예전 이름과 새로운 이름을 매핑할 수 있습니다.

노트: 지연 적재가 되는 객체 기반 체크포인트와는 달리 이름 기반 체크포인트는 함수가 호출될 때 모든 변수가 만들어 집니다. 일부 모델은 build 메서드를 호출하거나 배치 데이터에서 모델을 실행할 때까지 변수 생성을 지연합니다.

saved_model 호환성

saved_model에는 심각한 호환성 문제가 없습니다.

  • 텐서플로 1.x의 saved_model은 텐서플로 2.0와 호환됩니다.
  • 텐서플로 2.0의 saved_model로 저장한 모델도 연산이 지원된다면 TensorFlow 1.x에서 작동됩니다.

추정기

추정기로 훈련하기

텐서플로 2.0은 추정기(estimator)를 지원합니다.

추정기를 사용할 때 텐서플로 1.x의 input_fn(), tf.estimator.TrainSpec, tf.estimator.EvalSpec를 사용할 수 있습니다.

다음은 input_fn을 사용하여 훈련과 평가를 수행하는 예입니다.

input_fn과 훈련/평가 스펙 만들기

In [0]:

# 추정기 input_fn을 정의합니다.
def input_fn():
  datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)
  mnist_train, mnist_test = datasets['train'], datasets['test']

  BUFFER_SIZE = 10000
  BATCH_SIZE = 64

  def scale(image, label):
    image = tf.cast(image, tf.float32)
    image /= 255

    return image, label[..., tf.newaxis]

  train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
  return train_data.repeat()

# 훈련과 평가 스펙을 정의합니다.
train_spec = tf.estimator.TrainSpec(input_fn=input_fn,
                                    max_steps=STEPS_PER_EPOCH * NUM_EPOCHS)
eval_spec = tf.estimator.EvalSpec(input_fn=input_fn,
                                  steps=STEPS_PER_EPOCH)

케라스 모델 정의 사용하기

텐서플로 2.0에서 추정기를 구성하는 방법은 조금 다릅니다.

케라스를 사용하여 모델을 정의하는 것을 권장합니다. 그 다음 tf.keras.model_to_estimator 유틸리티를 사용하여 모델을 추정기로 바꾸세요. 다음 코드는 추정기를 만들고 훈련할 때 이 유틸리티를 사용하는 방법을 보여 줍니다.

In [0]:

def make_model():
  return tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.02),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10, activation='softmax')
  ])

In [0]:

model = make_model()

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

estimator = tf.keras.estimator.model_to_estimator(
  keras_model = model
)

tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)

맞춤형 model_fn 사용하기

기존에 작성한 맞춤형 추정기 model_fn을 유지해야 한다면 이 model_fn을 케라스 모델로 바꿀 수 있습니다.

그러나 호환성 때문에 맞춤형 model_fn은 1.x 스타일의 그래프 모드로 실행될 것입니다. 즉 즉시 실행과 의존성 자동 제어가 없다는 뜻입니다.

맞춤형 model_fn에 케라스 모델을 사용하는 것은 맞춤형 훈련 루프에 사용하는 것과 비슷합니다:

  • mode 매개변수에 기초하여 training 상태를 적절하게 지정하세요.
  • 옵티마이저에 모델의 trainable_variables를 명시적으로 전달하세요.

맞춤형 루프와 큰 차이점은 다음과 같습니다:

  • model.losses를 사용하는 대신 tf.keras.Model.get_losses_for 사용하여 손실을 추출하세요.
  • tf.keras.Model.get_updates_for를 사용하여 모델의 업데이트 값을 추출하세요.

노트: "업데이트(update)"는 각 배치가 끝난 후에 모델에 적용해야 할 변화량입니다. 예를 들면 tf.keras.layers.BatchNormalization 층에서 평균과 분산의 이동 평균(moving average)이 있습니다.

다음은 맞춤형 model_fn으로부터 추정기를 만드는 코드로 이런 개념을 잘 보여 줍니다.

In [0]:

def my_model_fn(features, labels, mode):
  model = make_model()

  optimizer = tf.compat.v1.train.AdamOptimizer()
  loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()

  training = (mode == tf.estimator.ModeKeys.TRAIN)
  predictions = model(features, training=training)

  reg_losses = model.get_losses_for(None) + model.get_losses_for(features)
  total_loss = loss_fn(labels, predictions) + tf.math.add_n(reg_losses)

  accuracy = tf.compat.v1.metrics.accuracy(labels=labels,
                                           predictions=tf.math.argmax(predictions, axis=1),
                                           name='acc_op')

  update_ops = model.get_updates_for(None) + model.get_updates_for(features)

  with tf.control_dependencies(update_ops):
    train_op = optimizer.minimize(
        total_loss,
        var_list=model.trainable_variables,
        global_step=tf.compat.v1.train.get_or_create_global_step())

  return tf.estimator.EstimatorSpec(
    mode=mode,
    predictions=predictions,
    loss=total_loss,
    train_op=train_op, eval_metric_ops={'accuracy': accuracy})

# 추정기를 만들고 훈련합니다.
estimator = tf.estimator.Estimator(model_fn=my_model_fn)
tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)

TensorShape

이 클래스는 tf.compat.v1.Dimension 객체 대신에 int 값을 가지도록 단순화되었습니다. 따라서 int 값을 얻기 위해 .value() 메서드를 호출할 필요가 없습니다.

여전히 개별 tf.compat.v1.Dimension 객체는 tf.TensorShape.dims로 참조할 수 있습니다.

다음 코드는 텐서플로 1.x와 텐서플로 2.0의 차이점을 보여줍니다.

In [0]:

# TensorShape 객체를 만들고 인덱스를 참조합니다.
i = 0
shape = tf.TensorShape([16, None, 256])
shape

TF 1.x에서는 다음과 같이 사용합니다:

value = shape[i].value

TF 2.0에서는 다음과 같이 사용합니다:

In [0]:

value = shape[i]
value

TF 1.x에서는 다음과 같이 사용합니다:

for dim in shape:
    value = dim.value
    print(value)

TF 2.0에서는 다음과 같이 사용합니다:

In [0]:

for value in shape:
  print(value)

TF 1.x에서는 다음과 같이 사용합니다(다른 Dimension 메서드를 사용할 때도):

dim = shape[i]
dim.assert_is_compatible_with(other_dim)

TF 2.0에서는 다음과 같이 사용합니다:

In [0]:

other_dim = 16
Dimension = tf.compat.v1.Dimension

if shape.rank is None:
  dim = Dimension(None)
else:
  dim = shape.dims[i]
dim.is_compatible_with(other_dim) # 다른 Dimension 메서드도 동일

In [0]:

shape = tf.TensorShape(None)

if shape:
  dim = shape.dims[i]
  dim.is_compatible_with(other_dim) # 다른 Dimension 메서드도 동일

랭크(rank)를 알 수 있다면 tf.TensorShape의 불리언 값은 True가 됩니다. 그렇지 않으면 False입니다.

In [0]:

print(bool(tf.TensorShape([])))      # 스칼라
print(bool(tf.TensorShape([0])))     # 길이 0인 벡터
print(bool(tf.TensorShape([1])))     # 길이 1인 벡터
print(bool(tf.TensorShape([None])))  # 길이를 알 수 없는 벡터
print(bool(tf.TensorShape([1, 10, 100])))       # 3D 텐서
print(bool(tf.TensorShape([None, None, None]))) # 크기를 모르는 3D 텐서
print()
print(bool(tf.TensorShape(None)))  # 랭크를 알 수 없는 텐서

그 밖의 동작 방식 변화

텐서플로 2.0에는 몇 가지 동작 방식의 변화가 있습니다.

ResourceVariables

텐서플로 2.0은 기본적으로 RefVariables가 아니라 ResourceVariables를 만듭니다.

ResourceVariables는 쓰기 금지가 되어 있어서 직관적으로 일관성이 더 잘 보장됩니다.

  • 이는 극단적인 경우 동작 방식에 변화를 일으킬 수 있습니다.
  • 경우에 따라서 추가적인 복사를 일으켜 메모리 사용량을 증가시킬 수 있습니다.
  • tf.Variable 생성자에 use_resource=False를 전달하여 비활성화시킬 수 있습니다.

제어 흐름

제어 흐름 연산의 구현이 단순화되었습니다. 따라서 텐서플로 2.0에서는 다른 그래프가 생성됩니다.

결론

전체적인 과정은 다음과 같습니다:

  1. 업그레이드 스크립트를 실행하세요.
  2. contrib 모듈을 삭제하세요.
  3. 모델을 객체 지향 스타일(케라스)로 바꾸세요.
  4. 가능한 tf.keras나 tf.estimator의 훈련과 평가 루프를 사용하세요.
  5. 그렇지 않으면 맞춤형 루프를 사용하세요. 세션과 컬렉션은 사용하지 말아야 합니다.

텐서플로 2.0 스타일로 코드를 바꾸려면 약간의 작업이 필요하지만 다음과 같은 장점을 얻을 수 있습니다:

  • 코드 라인이 줄어 듭니다.
  • 명료하고 단순해집니다.
  • 디버깅이 쉬워집니다.

1. 이미지 버퍼에서 cv::Mat 초기화 하기.

cv::Mat originFrame = cv::Mat(GetHeight(), GetWidth(), CV_8UC1, GetBits());





2. cv::Mat 의 영상을 BYTE 배열로 변환하기.


LPBYTE src = originFrame.data;
LPBYTE dst = GetBits();

if (src != dst)
{
	Concurrency::parallel_for(0l, (LONG)GetHeight(), [&](int y)
	{
		LPBYTE src_line = src + (y * originFrame.cols);
		LPBYTE dst_line = dst + (y * GetWidthBytes());
		memcpy(dst_line, src_line, GetWidth());
	});
}

구글 맵의 "내 타임라인" 링크를 클릭하면 아래와 같은 오류가 출력됩니다.



바로 400 에러...






해결 방법


'https://www.google.com/preferences'에서 국가를 '미국'으로 변경






아래 "지역 설정"에서 "자세히" 클릭



"미국" 설정 




+ Recent posts