F(x) = H(x) -x 에서 시작했는데 F(x)가 0이라고 생각하면 H(x) 와 x가 같을 수 밖에 없다.
여기서 시작해서 문제의 논지를 바꾸면
H(x) = F(x) + x 이렇게 볼 수 있다. x값이 커지면 F(x)값도 민감하게 바뀔 수 밖에 없다.
=> 이것을 Skip connection 이라 부름.

-> 스킵연결을 구현하는것은 덧셈 연산의 추가만으로 가능함. 이는 추가적인 연산량이나 파라미터가 많이 필요하지 않음. 또한 역전파 시에 그레디언트가 잘 흘러갈 수 있게 해준다는 장점이있다.

1x1이지만 다음에 곱해지는거에 따라서 사이즈가 달라짐
==> 이과정을 병목레이어(bottleneck layer)라 부른다.
# ResNet 블록 구조(bottleneck 구조) LayerBlock = namedtuple('LayerBlock', ['num_repeats', 'num_filters', 'bottleneck_size'])
import numpy as np import tensorflow as tf from collections import namedtuple from connections import conv2d, linear
이부분에서 에러가 날건데 잘 해결하는 방법 찾기,,,
resNet 프로젝트
1. connections.py를 저장하고 임포트 시킴.
- 기본적으로 stride가 2로 돼있기 때문에 따로 풀링을 하지않아도 기본값으로 1/2 샘플링이됨.
"""APL 2.0 code from github.com/pkmital/tensorflow_tutorials w/ permission from Parag K. Mital. """ import math import tensorflow as tf def batch_norm(x, phase_train, scope='bn', affine=True): """ Batch normalization on convolutional maps. from: https://stackoverflow.com/questions/33949786/how-could-i- use-batch-normalization-in-tensorflow Only modified to infer shape from input tensor x. Parameters ---------- x Tensor, 4D BHWD input maps phase_train boolean tf.Variable, true indicates training phase scope string, variable scope affine whether to affine-transform outputs Return ------ normed batch-normalized maps """ with tf.variable_scope(scope): og_shape = x.get_shape().as_list() if len(og_shape) == 2: x = tf.reshape(x, [-1, 1, 1, og_shape[1]]) shape = x.get_shape().as_list() beta = tf.Variable(tf.constant(0.0, shape=[shape[-1]]), name='beta', trainable=True) gamma = tf.Variable(tf.constant(1.0, shape=[shape[-1]]), name='gamma', trainable=affine) batch_mean, batch_var = tf.nn.moments(x, [0, 1, 2], name='moments') ema = tf.train.ExponentialMovingAverage(decay=0.9) ema_apply_op = ema.apply([batch_mean, batch_var]) ema_mean, ema_var = ema.average(batch_mean), ema.average(batch_var) def mean_var_with_update(): """Summary Returns ------- name : TYPE Description """ with tf.control_dependencies([ema_apply_op]): return tf.identity(batch_mean), tf.identity(batch_var) mean, var = tf.cond(phase_train, mean_var_with_update, lambda: (ema_mean, ema_var)) normed = tf.nn.batch_norm_with_global_normalization( x, mean, var, beta, gamma, 1e-3, affine) if len(og_shape) == 2: normed = tf.reshape(normed, [-1, og_shape[-1]]) return normed def lrelu(x, leak=0.2, name="lrelu"): """Leaky rectifier. Parameters ---------- x : Tensor The tensor to apply the nonlinearity to. leak : float, optional Leakage parameter. name : str, optional Variable scope to use. Returns ------- x : Tensor Output of the nonlinearity. """ with tf.variable_scope(name): f1 = 0.5 * (1 + leak) f2 = 0.5 * (1 - leak) return f1 * x + f2 * abs(x) def linear(x, n_units, scope=None, stddev=0.02, activation=lambda x: x): """Fully-connected network. Parameters ---------- x : Tensor Input tensor to the network. n_units : int Number of units to connect to. scope : str, optional Variable scope to use. stddev : float, optional Initialization's standard deviation. activation : arguments, optional Function which applies a nonlinearity Returns ------- x : Tensor Fully-connected output. """ shape = x.get_shape().as_list() with tf.variable_scope(scope or "Linear"): matrix = tf.get_variable("Matrix", [shape[1], n_units], tf.float32, tf.random_normal_initializer(stddev=stddev)) return activation(tf.matmul(x, matrix)) def conv2d(x, n_filters, k_h=5, k_w=5, stride_h=2, stride_w=2, stddev=0.02, activation=None, bias=True, padding='SAME', name="Conv2D"): """2D Convolution with options for kernel size, stride, and init deviation. Parameters ---------- x : Tensor Input tensor to convolve. n_filters : int Number of filters to apply. k_h : int, optional Kernel height. k_w : int, optional Kernel width. stride_h : int, optional Stride in rows. stride_w : int, optional Stride in cols. stddev : float, optional Initialization's standard deviation. activation : arguments, optional Function which applies a nonlinearity padding : str, optional 'SAME' or 'VALID' name : str, optional Variable scope to use. Returns ------- x : Tensor Convolved input. """ with tf.variable_scope(name): w = tf.get_variable( 'w', [k_h, k_w, x.get_shape()[-1], n_filters], initializer=tf.truncated_normal_initializer(stddev=stddev)) conv = tf.nn.conv2d( x, w, strides=[1, stride_h, stride_w, 1], padding=padding) if bias: b = tf.get_variable( 'b', [n_filters], initializer=tf.truncated_normal_initializer(stddev=stddev)) conv = tf.nn.bias_add(conv, b) if activation: conv = activation(conv) return conv
2. 필요한 모듈 임포트.
- 그래프 리셋은 왜?.. 어디서 쓰이지
import numpy as np import tensorflow as tf from collections import namedtuple from connections import conv2d, linear # 그래프 리셋 tf.reset_default_graph() # 재현성을 위해 시드 지정 tf.set_random_seed(1)
3. 자료 입력
- input_data를 다운받고 원핫코딩이 True인 상태로 가지고 옴.
- learning_rate = 0.0001
- epochs = 1 (원래는 100이나 간단히 실행시켜볼 요량으로 1이라고 지정함)
- batch_size = 100
- x : 28x28이므로 입력값으로 [None, 784]
- reshape : gray level 이기 때문에 [-1, 28, 28, 1] 로 형태변형을 해줌
- y : 10개의 숫자 분류위해서 [None, 10]
# 자료 입력 from tensorflow.examples.tutorials.mnist import input_data mnist=input_data.read_data_sets("MNIST_data/",one_hot=True) learning_rate=0.0001; epochs=1; batch_size=100 X=tf.placeholder(tf.float32,[None,784]) # 28x28 X_img=tf.reshape(X,[-1,28,28,1]) Y=tf.placeholder(tf.float32,[None,10])
4. 병목레이어를 만들기전 블록 구조 생성
- nametuplel : 이름과 값이 리스트로 들어가있는 튜플을 만듦
- 병목레이어를 만들 각 단계의 블록을 구성 (반복시킬 횟수, 필터수, 병목사이즈)
- 위에 resNet 구조에서 보았다시피 우리는 기본적으로 7x7 커널에 채널 64, stride를 2로 줌.
(* 이때 conv2d 함수안에 stride가 기본으로 2가 들어가 있기때문에 별도의 파라미터를 넣지않았는데도 14x14로 들어감)
- tf.nn.max_pool : 3x3 크기로 2칸씩 건너뛰며 맥스풀링을 해줌 -> 7x7x64
# ResNet 블록 구조(bottleneck 구조) LayerBlock = namedtuple('LayerBlock', ['num_repeats', 'num_filters', 'bottleneck_size']) blocks = [LayerBlock(3, 128, 32),LayerBlock(3, 256, 64),LayerBlock(3, 512, 128), LayerBlock(3, 1024, 256)] # 채널수 64의 합성곱 출력을 만들고 다운샘플링 net = conv2d(X_img, 64, k_h=7, k_w=7, name='conv1', activation=tf.nn.relu) # 14x14 net = tf.nn.max_pool(net, [1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME')
5. resNet 구조로 반복시켜 생성할 층 설계
- blocks[0].num_fileters : 128의 필터로 컨볼루션 층을 만듦 -> 7x7x128
- padding : VALID : 패딩을 전혀 넣지않음 (입출력이 같지 않아도 된다는말) - 왜?
- 첫번째 for문으로 blocks의 개수만큼 인덱스와 값을 가져옴
num_repeats의 개수만큼 두번째 for문안의 층을 다시 곱해줌
이때 conv1 층 padding : VALID, conv2 층 padding : SAME, conv3 층 padding : VALID 임을 주의.
- try~ except 구문은 단순히 예외처리인 부분일까 아니면 반드시 거치는 부분일까,,?
=> 이게 identity block
- net = conv3 + net : residual block의 연산
# ResNet 블록구조의 입력 생성 net = conv2d(net, blocks[0].num_filters, k_h=1, k_w=1, stride_h=1, stride_w=1, padding='VALID', name='conv2') ## (입력값, num_filters=128, ) # ResNet 블록 반복 for block_i, block in enumerate(blocks): for repeat_i in range(block.num_repeats): name = 'block_%d/repeat_%d' % (block_i, repeat_i) conv1 = conv2d(net, block.bottleneck_size, k_h=1, k_w=1, padding='VALID', stride_h=1, stride_w=1, activation=tf.nn.relu,name=name + '/conv_in') conv2 = conv2d(conv1, block.bottleneck_size, k_h=3, k_w=3, padding='SAME', stride_h=1, stride_w=1, activation=tf.nn.relu,name=name + '/conv_bottleneck') conv3 = conv2d(conv2, block.num_filters, k_h=1, k_w=1, padding='VALID', stride_h=1, stride_w=1, activation=tf.nn.relu, name=name + '/conv_out') net = conv3 + net try: # upscale to the next block size next_block = blocks[block_i + 1] net = conv2d(net, next_block.num_filters, k_h=1, k_w=1, padding='SAME', stride_h=1, stride_w=1, bias=False, name='block_%d/conv_upscale' % block_i) except IndexError: pass

6. 평균풀링과 softmax를 하기위해 최종출력을 1D 텐서로 바꿈
- avg_pool : flat 들어가기전에 global evg_pool 을 사용 (원래는 local) -> 레이어 사이즈가 줄지않음
# 평균 풀링을 이용하여 블록 구조의 최종 출력의 차원 변환 net = tf.nn.avg_pool(net, ksize=[1, net.get_shape().as_list()[1],net.get_shape().as_list()[2], 1], strides=[1, 1, 1, 1], padding='VALID') #ResNet 블록 구조의 최종 출력을 1D로 변환 Flat=tf.reshape(net,[-1, net.get_shape().as_list()[1] *net.get_shape().as_list()[2] *net.get_shape().as_list()[3]])
7. 최종출력
- activation으로 tf.nn.softmax 함수 지정
- cost는 사실상 여태 다뤄왔던 loss라고 볼 수 있음 - 최소제곱오차? 를 구함
- 옵티마이저 설정
# 최종 출력을 위해 소프트맥스함수 지정 Y_pred =linear(Flat, 10, activation=tf.nn.softmax) cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=Y_pred, labels=Y)) ## 손실.. optim=tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
8. 모델 정확도 분석위해 변수 선언, 정의
## 모델 정확도 correct_predict=tf.equal(tf.argmax(Y_pred,1), tf.argmax(Y,1)) accuracy=tf.reduce_mean(tf.cast(correct_predict, tf.float32))
9. 세션열고 초기화 (반드시 해야하는 부분)
- tf.global_variables : 반드시 global 초기화
sess=tf.Session(); sess.run(tf.global_variables_initializer())
10. epochs 만큼 훈련
- total_batch : 배치사이즈만큼 나누어진 집단을 받음
- 지정해준 optimizer 사용하여 최적화 하고 loss값을 구하고 평균 손실을 구함
- 정확도도 같이구함
- feed_dict : 무조건 placeholder -> 초기선언시
- W, b : 무조건 Variable -> 초기선언시
for epoch in range(epochs): avg_cost=0 total_batch=int(mnist.train.num_examples/batch_size) for i in range(total_batch): batch_xs,batch_ys=mnist.train.next_batch(batch_size) feed_dict={X:batch_xs, Y:batch_ys} sess.run(optim, feed_dict=feed_dict) ccost=sess.run(cost, feed_dict=feed_dict) ## 평균손실 avg_cost+=ccost/total_batch ## 왜? acc=sess.run(accuracy, feed_dict=feed_dict) print('Epoch: %d' %(epoch+1),'cost= %f, accuracy= %f' %(avg_cost, acc))
11.
# 훈련 데이터, 검정 데이터의 오분류율 acc_tr=0; acc_ts=0 for ii in range(100): #메모리 문제를 피하기 위해 자료를 100개로 분할 xr,yr=mnist.train.next_batch(550) acc_tr= acc_tr+ 0.01*sess.run(accuracy, feed_dict={X:xr, Y:yr}) xt,yt=mnist.test.next_batch(100) acc_ts= acc_ts+ 0.01*sess.run(accuracy, feed_dict={X:xt, Y:yt}) print('misclassification error(tr):', 1-acc_tr) print('misclassification error(ts):', 1-acc_ts)
Padding 계산하기
Output Size = (Input Size + 2 x Padding - Filter Size) / Stride + 1
'딥러닝' 카테고리의 다른 글
0814 RNN 구조로 뒤에올 문자 예측하기 (0) | 2019.08.14 |
---|---|
0814 embedding으로 단어 연관성 예측하기 (0) | 2019.08.14 |
0813 CNN으로 MNIST 분류기 구현하기 (0) | 2019.08.13 |
0812 ANN을 이용한 MNIST 숫자 분류기 구현 (0) | 2019.08.12 |
0812 소프트맥스 회귀로 MNIST 데이터 분석하기 (0) | 2019.08.12 |