imports

import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import tensorflow.experimental.numpy as tnp
tf.config.experimental.list_physical_devices()
[PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU'),
 PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
tnp.experimental_enable_numpy_behavior()
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.fashion_mnist.load_data()
y_train # 이 데이터는 클래스의 데이터
array([9, 0, 0, ..., 3, 0, 5], dtype=uint8)
x_train.shape
(60000, 28, 28)
X = tf.constant(x_train.reshape(-1,28,28,1),dtype=tf.float64)
y = tf.keras.utils.to_categorical(y_train)
XX = tf.constant(x_test.reshape(-1,28,28,1),dtype=tf.float64)
yy = tf.keras.utils.to_categorical(y_test)
net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Flatten())
net1.add(tf.keras.layers.Dense(30,activation='relu')) # 30 잘 안 맞는 거 아는데 처음이니까~ 해보자
net1.add(tf.keras.layers.Dense(30,activation='relu'))
net1.add(tf.keras.layers.Dense(10,activation='softmax'))
net1.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net1.fit(X,y,epochs=10)
Epoch 1/10
  53/1875 [..............................] - ETA: 5s - loss: 12.4897 - accuracy: 0.1285  
2022-05-20 14:32:32.348693: I tensorflow/stream_executor/cuda/cuda_blas.cc:1774] TensorFloat-32 will be used for the matrix multiplication. This will only be logged once.
1875/1875 [==============================] - 7s 3ms/step - loss: 1.7518 - accuracy: 0.4450
Epoch 2/10
1875/1875 [==============================] - 6s 3ms/step - loss: 1.0457 - accuracy: 0.5776
Epoch 3/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.9631 - accuracy: 0.6084
Epoch 4/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.9359 - accuracy: 0.6181
Epoch 5/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.9194 - accuracy: 0.6306
Epoch 6/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.8654 - accuracy: 0.6763
Epoch 7/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.7548 - accuracy: 0.7106
Epoch 8/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.7245 - accuracy: 0.7212
Epoch 9/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.7194 - accuracy: 0.7192
Epoch 10/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.7291 - accuracy: 0.7203
<keras.callbacks.History at 0x7f849c00b550>
net1.evaluate(XX,yy)
313/313 [==============================] - 1s 3ms/step - loss: 0.7162 - accuracy: 0.7168
[0.7161707878112793, 0.7167999744415283]
net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Flatten())
net1.add(tf.keras.layers.Dense(30,activation='relu')) # 30 잘 안 맞는 거 아는데 처음이니까~ 해보자
net1.add(tf.keras.layers.Dense(30,activation='relu'))
net1.add(tf.keras.layers.Dense(10,activation='softmax'))
net1.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net1.fit(X,y,epochs=20,verbose=0)
<keras.callbacks.History at 0x7f849c4cce80>
net1.evaluate(XX,yy)
313/313 [==============================] - 1s 3ms/step - loss: 0.5354 - accuracy: 0.8199
[0.5353805422782898, 0.8198999762535095]

net가 단순하다보니 정확도 계산에 한계가 있는 거 같다 에폭 20해도 크게 변하지 않음!

net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Flatten())
net1.add(tf.keras.layers.Dense(500,activation='relu'))
net1.add(tf.keras.layers.Dense(500,activation='relu'))
net1.add(tf.keras.layers.Dense(10,activation='softmax'))
net1.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net1.fit(X,y,epochs=10)
Epoch 1/10
1875/1875 [==============================] - 7s 4ms/step - loss: 2.1847 - accuracy: 0.7394
Epoch 2/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.6391 - accuracy: 0.7886
Epoch 3/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.5177 - accuracy: 0.8232
Epoch 4/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.4437 - accuracy: 0.8418
Epoch 5/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.4260 - accuracy: 0.8482
Epoch 6/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.4005 - accuracy: 0.8549
Epoch 7/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.3859 - accuracy: 0.8621
Epoch 8/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.3801 - accuracy: 0.8633
Epoch 9/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.3718 - accuracy: 0.8679
Epoch 10/10
1875/1875 [==============================] - 7s 4ms/step - loss: 0.3669 - accuracy: 0.8684
<keras.callbacks.History at 0x7f8420173e80>
net1.evaluate(XX,yy)
313/313 [==============================] - 1s 3ms/step - loss: 0.4506 - accuracy: 0.8496
[0.45062270760536194, 0.8496000170707703]
net1.summary()
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten_2 (Flatten)         (None, 784)               0         
                                                                 
 dense_6 (Dense)             (None, 500)               392500    
                                                                 
 dense_7 (Dense)             (None, 500)               250500    
                                                                 
 dense_8 (Dense)             (None, 10)                5010      
                                                                 
=================================================================
Total params: 648,010
Trainable params: 648,010
Non-trainable params: 0
_________________________________________________________________

Dense layer로 한계가 있는 것 같으니 다른 방법을 찾아보자


- 두번째 시도

  • tf.keras.layers.Conv2D
  • tf.keras.layers.MaxPool2D
net2 = tf.keras.Sequential()
net2.add(tf.keras.layers.Conv2D(30,(2,2)))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Conv2D(30,(2,2)))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Flatten())
net2.add(tf.keras.layers.Dense(10,activation='softmax'))
net2.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net2.fit(X,y,epochs=5)
Epoch 1/5
2022-05-20 14:41:39.740405: I tensorflow/stream_executor/cuda/cuda_dnn.cc:366] Loaded cuDNN version 8201
2022-05-20 14:41:40.496352: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory
2022-05-20 14:41:40.497384: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory
2022-05-20 14:41:40.497424: W tensorflow/stream_executor/gpu/asm_compiler.cc:80] Couldn't get ptxas version string: INTERNAL: Couldn't invoke ptxas --version
2022-05-20 14:41:40.498473: I tensorflow/core/platform/default/subprocess.cc:304] Start cannot spawn child process: No such file or directory
2022-05-20 14:41:40.498597: W tensorflow/stream_executor/gpu/redzone_allocator.cc:314] INTERNAL: Failed to launch ptxas
Relying on driver to perform ptx compilation. 
Modify $PATH to customize ptxas location.
This message will be only logged once.
1875/1875 [==============================] - 10s 4ms/step - loss: 1.4103 - accuracy: 0.8007
Epoch 2/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.4455 - accuracy: 0.8582
Epoch 3/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.3830 - accuracy: 0.8701
Epoch 4/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.3543 - accuracy: 0.8776
Epoch 5/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.3344 - accuracy: 0.8825
<keras.callbacks.History at 0x7f8398740460>
net2.evaluate(XX,yy)
313/313 [==============================] - 1s 4ms/step - loss: 0.3815 - accuracy: 0.8701
[0.3814590573310852, 0.8701000213623047]
net2.summary()
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (32, 27, 27, 30)          150       
                                                                 
 max_pooling2d (MaxPooling2D  (32, 13, 13, 30)         0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (32, 12, 12, 30)          3630      
                                                                 
 max_pooling2d_1 (MaxPooling  (32, 6, 6, 30)           0         
 2D)                                                             
                                                                 
 flatten_3 (Flatten)         (32, 1080)                0         
                                                                 
 dense_9 (Dense)             (32, 10)                  10810     
                                                                 
=================================================================
Total params: 14,590
Trainable params: 14,590
Non-trainable params: 0
_________________________________________________________________

dense에 파라메터 뭉쳐있는 이유

  • 펼쳐진 노드를 뭉치기 때문에..
  • 108010bias10개 = 10810 이렇게 계산되지!
  • 정확도만 보면 net2가 낫네?
  • 파라메터 수를 보니 첫번째 시도 대비 파라메터를 적게 사용한 모습을 볼 수 있다.

$\therefore$ 파라메터 조금쓰고 정확도 높은 좋은 net2모형!

net2.layers
[<keras.layers.convolutional.Conv2D at 0x7f83c8263a00>,
 <keras.layers.pooling.MaxPooling2D at 0x7f84344cb910>,
 <keras.layers.convolutional.Conv2D at 0x7f8434527be0>,
 <keras.layers.pooling.MaxPooling2D at 0x7f83c82632e0>,
 <keras.layers.core.flatten.Flatten at 0x7f83c82916f0>,
 <keras.layers.core.dense.Dense at 0x7f83c8291660>]

내가 설계한 네트워크의 순서를 확인해보자

c1,m1,c2,m2,flttn,dns = net2.layers
print(X.shape) # 입력이미지 = 2D # 1은 채널이 하나라는 뜻
print(c1(X).shape) # 2D # 갑자기 채널이 30이 되어버리!
print(m1(c1(X)).shape) # 2D # maxpool 통과했더니 fixel 크기가 줄어들었네?
print(c2(m1(c1(X))).shape) # 2D # 또 줄어들고 채널은 30으로 유지되는데?
print(m2(c2(m1(c1(X)))).shape) # 2D # 모두 퍼져서 12*12*30=4320이 되어버림
print(flttn(m2(c2(m1(c1(X))))).shape) # 2D
print(dns(flttn(m2(c2(m1(c1(X)))))).shape) # 2D
(60000, 28, 28, 1)
(60000, 27, 27, 30)
(60000, 13, 13, 30)
2022-05-20 14:44:38.071552: W tensorflow/core/kernels/gpu_utils.cc:49] Failed to allocate memory for convolution redzone checking; skipping this check. This is benign and only means that we won't check cudnn for out-of-bounds reads and writes. This message will only be printed once.
(60000, 12, 12, 30)
(60000, 6, 6, 30)
(60000, 1080)
(60000, 10)

밑에서 배우겠지만 27 ->13 갈때 행/열 하나씩 잘림(기본 옵션) 밑에서 보면 pooling='same;'쓰면 안 잘리고 쓰긴 함

채널 갑자기 믾아진 이유 어느것이든 맞추겠지!

net2 = tf.keras.Sequential()
net2.add(tf.keras.layers.Conv2D(30,(2,2),activation='relu'))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Conv2D(30,(2,2),activation='relu'))
net2.add(tf.keras.layers.MaxPool2D())
net2.add(tf.keras.layers.Flatten())
net2.add(tf.keras.layers.Dense(10,activation='softmax'))
net2.compile(optimizer='adam',loss=tf.losses.categorical_crossentropy,metrics='accuracy')
net2.fit(X,y,epochs=5)
Epoch 1/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.8637 - accuracy: 0.7969
Epoch 2/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.3873 - accuracy: 0.8627
Epoch 3/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.3449 - accuracy: 0.8747
Epoch 4/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.3242 - accuracy: 0.8837
Epoch 5/5
1875/1875 [==============================] - 8s 4ms/step - loss: 0.3030 - accuracy: 0.8894
<keras.callbacks.History at 0x7f839869add0>
net2.evaluate(XX,yy)
313/313 [==============================] - 1s 3ms/step - loss: 0.3729 - accuracy: 0.8755
[0.3728622794151306, 0.8755000233650208]

maxpooling2D

테스트1

m = tf.keras.layers.MaxPooling2D()
XXX = tnp.arange(1*4*4*1).reshape(1,4,4,1)
XXX # observation / color / channel
<tf.Tensor: shape=(1, 4, 4, 1), dtype=int64, numpy=
array([[[[ 0],
         [ 1],
         [ 2],
         [ 3]],

        [[ 4],
         [ 5],
         [ 6],
         [ 7]],

        [[ 8],
         [ 9],
         [10],
         [11]],

        [[12],
         [13],
         [14],
         [15]]]])>
m(XXX).reshape(1,2,2)
<tf.Tensor: shape=(1, 2, 2), dtype=int64, numpy=
array([[[ 5,  7],
        [13, 15]]])>

여기로 가는 mapping을 찾아볼까

XXX.reshape(1,4,4) #우리가 생각하는 이미지의 모습
<tf.Tensor: shape=(1, 4, 4), dtype=int64, numpy=
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11],
        [12, 13, 14, 15]]])>

[0,1,4,5] 중 max는 5

[2,3,6,7] 중 max는 7

[8,9,12,13] 중 max는 13

[10,11,14,15] 중 max는 15

- MaxPool2D layer의 역할: (2,2) 윈도우를 만들고 (2,2) 윈도우에서 max를 뽑아 값을 기록, 윈도우를 움직이면서 반복

테스트2

XXX = tnp.arange(1*6*6*1).reshape(1,6,6,1)
XXX.reshape(1,6,6) # 흑백 이미지라면 이렇게 보일 것
<tf.Tensor: shape=(1, 6, 6), dtype=int64, numpy=
array([[[ 0,  1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10, 11],
        [12, 13, 14, 15, 16, 17],
        [18, 19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28, 29],
        [30, 31, 32, 33, 34, 35]]])>
m(XXX).reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=int64, numpy=
array([[[ 7,  9, 11],
        [19, 21, 23],
        [31, 33, 35]]])>

테스트3

tf.keras.layers.MaxPooling2D??

Init signature:
tf.keras.layers.MaxPooling2D(
    pool_size=(2, 2),
    strides=None,
    padding='valid',
    data_format=None,
    **kwargs,
)
Source:        
@keras_export('keras.layers.MaxPool2D', 'keras.layers.MaxPooling2D')
class MaxPooling2D(Pooling2D):
  """Max pooling operation for 2D spatial data.

  Downsamples the input along its spatial dimensions (height and width)
  by taking the maximum value over an input window
  (of size defined by `pool_size`) for each channel of the input.
  The window is shifted by `strides` along each dimension.

  The resulting output,
  when using the `"valid"` padding option, has a spatial shape
  (number of rows or columns) of:
  `output_shape = math.floor((input_shape - pool_size) / strides) + 1`
  (when `input_shape >= pool_size`)

  The resulting output shape when using the `"same"` padding option is:
  `output_shape = math.floor((input_shape - 1) / strides) + 1`

  For example, for `strides=(1, 1)` and `padding="valid"`:

  >>> x = tf.constant([[1., 2., 3.],
  ...                  [4., 5., 6.],
  ...                  [7., 8., 9.]])
  >>> x = tf.reshape(x, [1, 3, 3, 1])
  >>> max_pool_2d = tf.keras.layers.MaxPooling2D(pool_size=(2, 2),
  ...    strides=(1, 1), padding='valid')
  >>> max_pool_2d(x)
  <tf.Tensor: shape=(1, 2, 2, 1), dtype=float32, numpy=
    array([[[[5.],
             [6.]],
            [[8.],
             [9.]]]], dtype=float32)>

  For example, for `strides=(2, 2)` and `padding="valid"`:

  >>> x = tf.constant([[1., 2., 3., 4.],
  ...                  [5., 6., 7., 8.],
  ...                  [9., 10., 11., 12.]])
  >>> x = tf.reshape(x, [1, 3, 4, 1])
  >>> max_pool_2d = tf.keras.layers.MaxPooling2D(pool_size=(2, 2),
  ...    strides=(2, 2), padding='valid')
  >>> max_pool_2d(x)
  <tf.Tensor: shape=(1, 1, 2, 1), dtype=float32, numpy=
    array([[[[6.],
             [8.]]]], dtype=float32)>

  Usage Example:

  >>> input_image = tf.constant([[[[1.], [1.], [2.], [4.]],
  ...                            [[2.], [2.], [3.], [2.]],
  ...                            [[4.], [1.], [1.], [1.]],
  ...                            [[2.], [2.], [1.], [4.]]]])
  >>> output = tf.constant([[[[1], [0]],
  ...                       [[0], [1]]]])
  >>> model = tf.keras.models.Sequential()
  >>> model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2),
  ...    input_shape=(4, 4, 1)))
  >>> model.compile('adam', 'mean_squared_error')
  >>> model.predict(input_image, steps=1)
  array([[[[2.],
           [4.]],
          [[4.],
           [4.]]]], dtype=float32)

  For example, for stride=(1, 1) and padding="same":

  >>> x = tf.constant([[1., 2., 3.],
  ...                  [4., 5., 6.],
  ...                  [7., 8., 9.]])
  >>> x = tf.reshape(x, [1, 3, 3, 1])
  >>> max_pool_2d = tf.keras.layers.MaxPooling2D(pool_size=(2, 2),
  ...    strides=(1, 1), padding='same')
  >>> max_pool_2d(x)
  <tf.Tensor: shape=(1, 3, 3, 1), dtype=float32, numpy=
    array([[[[5.],
             [6.],
             [6.]],
            [[8.],
             [9.],
             [9.]],
            [[8.],
             [9.],
             [9.]]]], dtype=float32)>

  Args:
    pool_size: integer or tuple of 2 integers,
      window size over which to take the maximum.
      `(2, 2)` will take the max value over a 2x2 pooling window.
      If only one integer is specified, the same window length
      will be used for both dimensions.
    strides: Integer, tuple of 2 integers, or None.
      Strides values.  Specifies how far the pooling window moves
      for each pooling step. If None, it will default to `pool_size`.
    padding: One of `"valid"` or `"same"` (case-insensitive).
      `"valid"` means no padding. `"same"` results in padding evenly to
      the left/right or up/down of the input such that output has the same
      height/width dimension as the input.
    data_format: A string,
      one of `channels_last` (default) or `channels_first`.
      The ordering of the dimensions in the inputs.
      `channels_last` corresponds to inputs with shape
      `(batch, height, width, channels)` while `channels_first`
      corresponds to inputs with shape
      `(batch, channels, height, width)`.
      It defaults to the `image_data_format` value found in your
      Keras config file at `~/.keras/keras.json`.
      If you never set it, then it will be "channels_last".

  Input shape:
    - If `data_format='channels_last'`:
      4D tensor with shape `(batch_size, rows, cols, channels)`.
    - If `data_format='channels_first'`:
      4D tensor with shape `(batch_size, channels, rows, cols)`.

  Output shape:
    - If `data_format='channels_last'`:
      4D tensor with shape `(batch_size, pooled_rows, pooled_cols, channels)`.
    - If `data_format='channels_first'`:
      4D tensor with shape `(batch_size, channels, pooled_rows, pooled_cols)`.

  Returns:
    A tensor of rank 4 representing the maximum pooled values.  See above for
    output shape.
  """

  def __init__(self,
               pool_size=(2, 2),
               strides=None,
               padding='valid',
               data_format=None,
               **kwargs):
    super(MaxPooling2D, self).__init__(
        tf.compat.v1.nn.max_pool,
        pool_size=pool_size, strides=strides,
        padding=padding, data_format=data_format, **kwargs)
File:           ~/anaconda3/envs/stbda2022/lib/python3.10/site-packages/keras/layers/pooling.py
Type:           type
Subclasses:     MaxPooling2D
m = tf.keras.layers.MaxPooling2D(pool_size=(3,3))
XXX = tnp.arange(1*6*6*1).reshape(1,6,6,1)
XXX.reshape(1,6,6) # 흑백 이미지라면 이렇게 보일 것
<tf.Tensor: shape=(1, 6, 6), dtype=int64, numpy=
array([[[ 0,  1,  2,  3,  4,  5],
        [ 6,  7,  8,  9, 10, 11],
        [12, 13, 14, 15, 16, 17],
        [18, 19, 20, 21, 22, 23],
        [24, 25, 26, 27, 28, 29],
        [30, 31, 32, 33, 34, 35]]])>
m(XXX).reshape(1,2,2)
<tf.Tensor: shape=(1, 2, 2), dtype=int64, numpy=
array([[[14, 17],
        [32, 35]]])>

테스트4

m = tf.keras.layers.MaxPooling2D(pool_size=(2,2))
XXX = tnp.arange(1*5*5*1).reshape(1,5,5,1)
XXX.reshape(1,5,5) # 흑백 이미지라면 이렇게 보일 것
<tf.Tensor: shape=(1, 5, 5), dtype=int64, numpy=
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19],
        [20, 21, 22, 23, 24]]])>
m(XXX).reshape(1,2,2)
<tf.Tensor: shape=(1, 2, 2), dtype=int64, numpy=
array([[[ 6,  8],
        [16, 18]]])>

애매한 열/행 수를 넣어주니 마지막 열/행은 버려버리네!

  • 차원이 안 맞으면 버려버림( 기본 옵션)
m = tf.keras.layers.MaxPooling2D(pool_size=(2,2),padding='same')
XXX = tnp.arange(1*5*5*1).reshape(1,5,5,1)
XXX.reshape(1,5,5) # 흑백 이미지라면 이렇게 보일 것
<tf.Tensor: shape=(1, 5, 5), dtype=int64, numpy=
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19],
        [20, 21, 22, 23, 24]]])>
m(XXX).reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=int64, numpy=
array([[[ 6,  8,  9],
        [16, 18, 19],
        [21, 23, 24]]])>

padding ="same" 옵션을 넣어주니 차원을 버리지 않고 다 사용하네?

  • 균형을 맞춰 구하진 않음
  • 24의 경우 24 하나의 값 중에서 큰 값인 24를 택한 것.

테스트5

XXX = tnp.arange(2*4*4*1).reshape(2,4,4,1)
XXX.reshape(2,4,4)
<tf.Tensor: shape=(2, 4, 4), dtype=int64, numpy=
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11],
        [12, 13, 14, 15]],

       [[16, 17, 18, 19],
        [20, 21, 22, 23],
        [24, 25, 26, 27],
        [28, 29, 30, 31]]])>
m(XXX).reshape(2,2,2)
<tf.Tensor: shape=(2, 2, 2), dtype=int64, numpy=
array([[[ 5,  7],
        [13, 15]],

       [[21, 23],
        [29, 31]]])>

테스트5

XXX = tnp.arange(1*4*4*3).reshape(1,4,4,3) # observation 1 channel 3으로 고정
XXX[:,:,:,0]
<tf.Tensor: shape=(1, 4, 4), dtype=int64, numpy=
array([[[ 0,  3,  6,  9],
        [12, 15, 18, 21],
        [24, 27, 30, 33],
        [36, 39, 42, 45]]])>

위 아래 같은 결과..! 생략구문이라 부른다.

XXX[...,0]
<tf.Tensor: shape=(1, 4, 4), dtype=int64, numpy=
array([[[ 0,  3,  6,  9],
        [12, 15, 18, 21],
        [24, 27, 30, 33],
        [36, 39, 42, 45]]])>
m(XXX)[:,:,:,0]
<tf.Tensor: shape=(1, 2, 2), dtype=int64, numpy=
array([[[15, 21],
        [39, 45]]])>
m(XXX)[...,0]
<tf.Tensor: shape=(1, 2, 2), dtype=int64, numpy=
array([[[15, 21],
        [39, 45]]])>

Conv2d

테스트1

- 레이어 생성

cnv = tf.keras.layers.Conv2D(1,(2,2))
cnv
<keras.layers.convolutional.Conv2D at 0x7f8398687c70>

- XXX 생성

XXX = tnp.arange(1*4*4*1).reshape(1,4,4,1)
XXX.reshape(1,4,4)
<tf.Tensor: shape=(1, 4, 4), dtype=int64, numpy=
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11],
        [12, 13, 14, 15]]])>

힘든 점:;; 이대로 넣으면 안 돌아간다.

  • 데이터 타입이 int가 아니라 float이어야 한다.
cnv(XXX)
---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
Input In [56], in <cell line: 1>()
----> 1 cnv(XXX)

File ~/anaconda3/envs/stbda2022/lib/python3.10/site-packages/keras/utils/traceback_utils.py:67, in filter_traceback.<locals>.error_handler(*args, **kwargs)
     65 except Exception as e:  # pylint: disable=broad-except
     66   filtered_tb = _process_traceback_frames(e.__traceback__)
---> 67   raise e.with_traceback(filtered_tb) from None
     68 finally:
     69   del filtered_tb

File ~/anaconda3/envs/stbda2022/lib/python3.10/site-packages/tensorflow/python/framework/ops.py:7107, in raise_from_not_ok_status(e, name)
   7105 def raise_from_not_ok_status(e, name):
   7106   e.message += (" name: " + name if name is not None else "")
-> 7107   raise core._status_to_exception(e) from None

InvalidArgumentError: Exception encountered when calling layer "conv2d_4" (type Conv2D).

Value for attr 'T' of int64 is not in the list of allowed values: half, bfloat16, float, double, int32
	; NodeDef: {{node Conv2D}}; Op<name=Conv2D; signature=input:T, filter:T -> output:T; attr=T:type,allowed=[DT_HALF, DT_BFLOAT16, DT_FLOAT, DT_DOUBLE, DT_INT32]; attr=strides:list(int); attr=use_cudnn_on_gpu:bool,default=true; attr=padding:string,allowed=["SAME", "VALID", "EXPLICIT"]; attr=explicit_paddings:list(int),default=[]; attr=data_format:string,default="NHWC",allowed=["NHWC", "NCHW"]; attr=dilations:list(int),default=[1, 1, 1, 1]> [Op:Conv2D]

Call arguments received:
  • inputs=tf.Tensor(shape=(1, 4, 4, 1), dtype=int64)
XXX = tnp.arange(1*4*4*1,dtype=tf.float64).reshape(1,4,4,1)
XXX.reshape(1,4,4)
<tf.Tensor: shape=(1, 4, 4), dtype=float64, numpy=
array([[[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  6.,  7.],
        [ 8.,  9., 10., 11.],
        [12., 13., 14., 15.]]])>
cnv(XXX)
<tf.Tensor: shape=(1, 3, 3, 1), dtype=float32, numpy=
array([[[[-1.0253725],
         [-1.8695811],
         [-2.7137897]],

        [[-4.402207 ],
         [-5.246415 ],
         [-6.090624 ]],

        [[-7.7790413],
         [-8.62325  ],
         [-9.467459 ]]]], dtype=float32)>
  • 꼭 4 차원이어야 한다.
XXX = tnp.arange(1*3*3*1,dtype=tf.float64).reshape(1,3,3,1)
XXX.reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=float64, numpy=
array([[[0., 1., 2.],
        [3., 4., 5.],
        [6., 7., 8.]]])>
cnv(XXX)
<tf.Tensor: shape=(1, 2, 2, 1), dtype=float32, numpy=
array([[[[-0.73827314],
         [-1.5824816 ]],

        [[-3.2708988 ],
         [-4.1151075 ]]]], dtype=float32)>
XXX = tnp.arange(1*4*4*1,dtype=tf.float64).reshape(1,4,4,1)
XXX.reshape(1,4,4)
<tf.Tensor: shape=(1, 4, 4), dtype=float64, numpy=
array([[[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  6.,  7.],
        [ 8.,  9., 10., 11.],
        [12., 13., 14., 15.]]])>
cnv(XXX).reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=float32, numpy=
array([[[-1.0253725, -1.8695811, -2.7137897],
        [-4.402207 , -5.246415 , -6.090624 ],
        [-7.7790413, -8.62325  , -9.467459 ]]], dtype=float32)>
  • XXX에서 cnv(XXX)로 가는 맵핑을 찾는 건 쉽지 않아 보인다
  • 심지어 랜덤으로 결정되는 부분도 있어보인다.

- 코드 정리

tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(2,2))
XXX = tnp.arange(1*4*4*1,dtype=tf.float64).reshape(1,4,4,1)
print(XXX.reshape(1,4,4))
print(cnv(XXX).reshape(1,3,3))
tf.Tensor(
[[[ 0.  1.  2.  3.]
  [ 4.  5.  6.  7.]
  [ 8.  9. 10. 11.]
  [12. 13. 14. 15.]]], shape=(1, 4, 4), dtype=float64)
tf.Tensor(
[[[ -4.125754   -5.312817   -6.4998803]
  [ -8.874006  -10.0610695 -11.248133 ]
  [-13.622259  -14.809322  -15.996386 ]]], shape=(1, 3, 3), dtype=float32)

dense 때와 비슷한 상황

cnv.weights
[<tf.Variable 'conv2d_5/kernel:0' shape=(2, 2, 1, 1) dtype=float32, numpy=
 array([[[[-0.13014299]],
 
         [[-0.23927206]]],
 
 
        [[[-0.20175874]],
 
         [[-0.6158894 ]]]], dtype=float32)>,
 <tf.Variable 'conv2d_5/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]
type(cnv.weights)
list
cnv.weights[0]
<tf.Variable 'conv2d_5/kernel:0' shape=(2, 2, 1, 1) dtype=float32, numpy=
array([[[[-0.13014299]],

        [[-0.23927206]]],


       [[[-0.20175874]],

        [[-0.6158894 ]]]], dtype=float32)>
tf.reshape(cnv.weights[0],(2,2))
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[-0.13014299, -0.23927206],
       [-0.20175874, -0.6158894 ]], dtype=float32)>

어떻게 유추될까?

0 * -0.13014299 + 1 *  -0.23927206 + 4 * -0.20175874 + 5 *  -0.6158894 + 0
-4.1257540200000005

값이 나왔네

  • 원래는 위에서 bias가 들어가야 하지, 위 식에서는 bias가 0임
cnv.get_weights()
[array([[[[-0.13014299]],
 
         [[-0.23927206]]],
 
 
        [[[-0.20175874]],
 
         [[-0.6158894 ]]]], dtype=float32),
 array([0.], dtype=float32)]

2개 나온 모습

type(cnv.get_weights())
list
type(cnv.get_weights()[0])
numpy.ndarray
type(cnv.get_weights()[1])
numpy.ndarray
cnv.get_weights()[0].shape
(2, 2, 1, 1)
cnv.get_weights()[1].shape
(1,)
w = np.array([1/4,1/4,1/4,1/4],dtype=np.float32).reshape(2,2,1,1)
b = np.array([3],dtype=np.float32)

b는 bias인거 알지? 밑 weights에서 확인 가능

[w,b]
[array([[[[0.25]],
 
         [[0.25]]],
 
 
        [[[0.25]],
 
         [[0.25]]]], dtype=float32),
 array([3.], dtype=float32)]

같은 형식으로 나오게 만들었다.

cnv.set_weights([w,b])
cnv.weights
[<tf.Variable 'conv2d_5/kernel:0' shape=(2, 2, 1, 1) dtype=float32, numpy=
 array([[[[0.25]],
 
         [[0.25]]],
 
 
        [[[0.25]],
 
         [[0.25]]]], dtype=float32)>,
 <tf.Variable 'conv2d_5/bias:0' shape=(1,) dtype=float32, numpy=array([3.], dtype=float32)>]
XXX.reshape(1,4,4)
<tf.Tensor: shape=(1, 4, 4), dtype=float64, numpy=
array([[[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  6.,  7.],
        [ 8.,  9., 10., 11.],
        [12., 13., 14., 15.]]])>
cnv(XXX).reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=float32, numpy=
array([[[ 5.5,  6.5,  7.5],
        [ 9.5, 10.5, 11.5],
        [13.5, 14.5, 15.5]]], dtype=float32)>
np.mean([0,1,4,5])+3, np.mean([1,2,5,6])+3, np.mean([2,3,6,7])+3
(5.5, 6.5, 7.5)

겹치지 않는 MaxPooling과 달리 겹치는 ConV2D

tf.keras.layers.Conv2D(1,kernel_size=(2,2)) 요약

(1) size=(2,2)인 윈도우를 만듦.

(2) XXX에 윈도우를 통과시켜서 (2,2)크기의 sub XXX 를 얻음. sub XXX의 각 원소에 conv2d.weights[0]의 각 원소를 element-wise하게 곱한다.

  • sub XXX의 의미는 위에서 0,1,4,5(XXX.reshape(1,4,4) 결과 중 일부)를 의미

(3) (2)의 결과를 모두 더한다. 그리고 그 결과에 다시 conv2d.weights[1]을 수행

(4) 윈도우를 이동시키면서 반복!

테스트2

커널을 늘려보자

tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(3,3))
XXX = tnp.arange(1*5*5*1,dtype=tf.float64).reshape(1,5,5,1)
XXX.reshape(1,5,5)
<tf.Tensor: shape=(1, 5, 5), dtype=float64, numpy=
array([[[ 0.,  1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.,  9.],
        [10., 11., 12., 13., 14.],
        [15., 16., 17., 18., 19.],
        [20., 21., 22., 23., 24.]]])>
cnv(XXX).reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=float32, numpy=
array([[[ 2.7395768 ,  2.2492635 ,  1.7589504 ],
        [ 0.28801066, -0.20230258, -0.6926158 ],
        [-2.1635566 , -2.6538715 , -3.1441827 ]]], dtype=float32)>

2.7395768 재현 해보기

cnv.weights[1]
<tf.Variable 'conv2d_6/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>

bias term은 보통 0이야..

XXX.reshape(1,5,5)
<tf.Tensor: shape=(1, 5, 5), dtype=float64, numpy=
array([[[ 0.,  1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.,  9.],
        [10., 11., 12., 13., 14.],
        [15., 16., 17., 18., 19.],
        [20., 21., 22., 23., 24.]]])>
XXX.reshape(1,5,5)[0,:3,:3]
<tf.Tensor: shape=(3, 3), dtype=float64, numpy=
array([[ 0.,  1.,  2.],
       [ 5.,  6.,  7.],
       [10., 11., 12.]])>
tf.reshape(cnv.weights[0],(3,3))
<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[-0.08676198, -0.1595147 , -0.13450584],
       [-0.4105929 , -0.38366908,  0.07744962],
       [-0.09255642,  0.4915564 ,  0.20828158]], dtype=float32)>
tf.reduce_sum(XXX.reshape(1,5,5)[0,:3,:3] * tf.reshape(cnv.weights[0],(3,3)))
<tf.Tensor: shape=(), dtype=float64, numpy=2.739577144384384>

나왔다.

  • 요소끼리 곱 * 쓸 수 있는 거 기억해..

테스트3

3*0 + 3*1 + 2*2  +0*2 + 0*2 + 1*0 + 3*0 + 1*1 + 2*2
12

하나만 해보기


내가 한 거!

tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(3,3))
XXX = np.array([3,3,2,1,0,0,0,1,3,1,3,1,2,2,3,2,0,0,2,2,2,0,0,0,1]).reshape(1,5,5,1)
XXX.reshape(1,5,5)
array([[[3, 3, 2, 1, 0],
        [0, 0, 1, 3, 1],
        [3, 1, 2, 2, 3],
        [2, 0, 0, 2, 2],
        [2, 0, 0, 0, 1]]])
XXX.reshape(1,5,5)[0,2:,:3]
array([[3, 1, 2],
       [2, 0, 0],
       [2, 0, 0]])
_w = np.array([0,1,2,2,2,0,0,1,2],dtype=np.float32).reshape(3,3,1,1)
_b = np.array([0],dtype=np.float32)
cnv
<keras.layers.convolutional.Conv2D at 0x7f8398699ed0>
cnv(XXX)
---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
Input In [97], in <cell line: 1>()
----> 1 cnv(XXX)

File ~/anaconda3/envs/stbda2022/lib/python3.10/site-packages/keras/utils/traceback_utils.py:67, in filter_traceback.<locals>.error_handler(*args, **kwargs)
     65 except Exception as e:  # pylint: disable=broad-except
     66   filtered_tb = _process_traceback_frames(e.__traceback__)
---> 67   raise e.with_traceback(filtered_tb) from None
     68 finally:
     69   del filtered_tb

File ~/anaconda3/envs/stbda2022/lib/python3.10/site-packages/tensorflow/python/framework/ops.py:7107, in raise_from_not_ok_status(e, name)
   7105 def raise_from_not_ok_status(e, name):
   7106   e.message += (" name: " + name if name is not None else "")
-> 7107   raise core._status_to_exception(e) from None

InvalidArgumentError: Exception encountered when calling layer "conv2d_7" (type Conv2D).

Value for attr 'T' of int64 is not in the list of allowed values: half, bfloat16, float, double, int32
	; NodeDef: {{node Conv2D}}; Op<name=Conv2D; signature=input:T, filter:T -> output:T; attr=T:type,allowed=[DT_HALF, DT_BFLOAT16, DT_FLOAT, DT_DOUBLE, DT_INT32]; attr=strides:list(int); attr=use_cudnn_on_gpu:bool,default=true; attr=padding:string,allowed=["SAME", "VALID", "EXPLICIT"]; attr=explicit_paddings:list(int),default=[]; attr=data_format:string,default="NHWC",allowed=["NHWC", "NCHW"]; attr=dilations:list(int),default=[1, 1, 1, 1]> [Op:Conv2D]

Call arguments received:
  • inputs=tf.Tensor(shape=(1, 5, 5, 1), dtype=int64)
cnv.get_weights()[0]
array([[[[-0.08676198]],

        [[-0.1595147 ]],

        [[-0.13450584]]],


       [[[-0.4105929 ]],

        [[-0.38366908]],

        [[ 0.07744962]]],


       [[[-0.09255642]],

        [[ 0.4915564 ]],

        [[ 0.20828158]]]], dtype=float32)
cnv.set_weights([_w,_b])
cnv.get_weights
<bound method Layer.get_weights of <keras.layers.convolutional.Conv2D object at 0x7f8398699ed0>>
tf.reduce_sum(XXX.reshape(1,5,5)[0,2:,:3] * tf.reshape(cnv.weights[0],(3,3)))
<tf.Tensor: shape=(), dtype=float64, numpy=9.0>

- 교수님 부분

XXX = tf.constant([[3,3,2,1,0],[0,0,1,3,1],[3,1,2,2,3],[2,0,0,2,2],[2,0,0,0,1]],dtype=tf.float64).reshape(1,5,5,1)
XXX.reshape(1,5,5)
<tf.Tensor: shape=(1, 5, 5), dtype=float64, numpy=
array([[[3., 3., 2., 1., 0.],
        [0., 0., 1., 3., 1.],
        [3., 1., 2., 2., 3.],
        [2., 0., 0., 2., 2.],
        [2., 0., 0., 0., 1.]]])>
  • 데이터 타입이 float이어야 한다.

  • shape 이 1 5 5 * 1 이어야 한다.

cnv = tf.keras.layers.Conv2D(1,(3,3))
cnv(XXX).reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=float32, numpy=
array([[[-0.6065799 , -0.69143724, -1.1179221 ],
        [ 2.2352955 ,  1.5314975 ,  1.8658445 ],
        [ 0.7364182 ,  1.4419123 ,  1.2381717 ]]], dtype=float32)>

Warning: 위처럼 한 번 통과시켜줘야 weights가 나옴!!!
cnv.weights[0]
<tf.Variable 'conv2d_8/kernel:0' shape=(3, 3, 1, 1) dtype=float32, numpy=
array([[[[-0.3444655 ]],

        [[ 0.4521824 ]],

        [[ 0.236296  ]]],


       [[[ 0.54707503]],

        [[ 0.19746327]],

        [[ 0.20471048]]],


       [[[-0.1245549 ]],

        [[-0.25237298]],

        [[-0.4904977 ]]]], dtype=float32)>
_w = tf.constant([[0,1,2,],[2,2,0],[0,1,2]],dtype=tf.float64).reshape(3,3,1,1)
_b = tf.constant([0],dtype=tf.float64)
cnv.set_weights([_w,_b])
cnv.weights
[<tf.Variable 'conv2d_8/kernel:0' shape=(3, 3, 1, 1) dtype=float32, numpy=
 array([[[[0.]],
 
         [[1.]],
 
         [[2.]]],
 
 
        [[[2.]],
 
         [[2.]],
 
         [[0.]]],
 
 
        [[[0.]],
 
         [[1.]],
 
         [[2.]]]], dtype=float32)>,
 <tf.Variable 'conv2d_8/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]
cnv(XXX).reshape(1,3,3)
<tf.Tensor: shape=(1, 3, 3), dtype=float32, numpy=
array([[[12., 12., 17.],
        [10., 17., 19.],
        [ 9.,  6., 14.]]], dtype=float32)>

테스트4

observation 마다 반복하게 한다?

tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(1,(2,2))
XXX = tnp.arange(2*5*5*1,dtype=tf.float64).reshape(2,5,5,1)
XXX.reshape(2,5,5)
<tf.Tensor: shape=(2, 5, 5), dtype=float64, numpy=
array([[[ 0.,  1.,  2.,  3.,  4.],
        [ 5.,  6.,  7.,  8.,  9.],
        [10., 11., 12., 13., 14.],
        [15., 16., 17., 18., 19.],
        [20., 21., 22., 23., 24.]],

       [[25., 26., 27., 28., 29.],
        [30., 31., 32., 33., 34.],
        [35., 36., 37., 38., 39.],
        [40., 41., 42., 43., 44.],
        [45., 46., 47., 48., 49.]]])>
cnv.weights
[]
cnv(XXX)
<tf.Tensor: shape=(2, 4, 4, 1), dtype=float32, numpy=
array([[[[ -4.943402 ],
         [ -6.130465 ],
         [ -7.3175282],
         [ -8.504592 ]],

        [[-10.878717 ],
         [-12.065781 ],
         [-13.252845 ],
         [-14.439907 ]],

        [[-16.814034 ],
         [-18.001097 ],
         [-19.18816  ],
         [-20.375223 ]],

        [[-22.74935  ],
         [-23.936413 ],
         [-25.123476 ],
         [-26.31054  ]]],


       [[[-34.61998  ],
         [-35.807045 ],
         [-36.994106 ],
         [-38.18117  ]],

        [[-40.555298 ],
         [-41.74236  ],
         [-42.929424 ],
         [-44.116486 ]],

        [[-46.490612 ],
         [-47.677677 ],
         [-48.86474  ],
         [-50.051804 ]],

        [[-52.425926 ],
         [-53.61299  ],
         [-54.800053 ],
         [-55.987118 ]]]], dtype=float32)>

layer 한 번 통과시켜줘야 weights이 나오지

cnv.weights
[<tf.Variable 'conv2d_9/kernel:0' shape=(2, 2, 1, 1) dtype=float32, numpy=
 array([[[[-0.13014299]],
 
         [[-0.23927206]]],
 
 
        [[[-0.20175874]],
 
         [[-0.6158894 ]]]], dtype=float32)>,
 <tf.Variable 'conv2d_9/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]
cnv.set_weights([w,b])
cnv(XXX).reshape(2,4,4)
<tf.Tensor: shape=(2, 4, 4), dtype=float32, numpy=
array([[[ 6.,  7.,  8.,  9.],
        [11., 12., 13., 14.],
        [16., 17., 18., 19.],
        [21., 22., 23., 24.]],

       [[31., 32., 33., 34.],
        [36., 37., 38., 39.],
        [41., 42., 43., 44.],
        [46., 47., 48., 49.]]], dtype=float32)>
print(cnv(XXX).reshape(2,4,4))
tf.Tensor(
[[[ 6.  7.  8.  9.]
  [11. 12. 13. 14.]
  [16. 17. 18. 19.]
  [21. 22. 23. 24.]]

 [[31. 32. 33. 34.]
  [36. 37. 38. 39.]
  [41. 42. 43. 44.]
  [46. 47. 48. 49.]]], shape=(2, 4, 4), dtype=float32)
np.mean([0,1,5,6])+3,np.mean([1,2,6,7])+3,np.mean([25,26,30,31])+3
(6.0, 7.0, 31.0)

테스트5

-

observation이 고정이고 출력 채널이 바뀔때

tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(4,(2,2))
XXX = tnp.arange(1*2*2*1,dtype=tf.float64).reshape(1,2,2,1)

Note: cnv = tf.keras.layers.Conv2D(4,(2,2)) 여기서 activation ’relu’주면 음의 값이 다 0이 되겠지 뭐~
print(XXX.reshape(1,2,2))
tf.Tensor(
[[[0. 1.]
  [2. 3.]]], shape=(1, 2, 2), dtype=float64)
cnv(XXX)
<tf.Tensor: shape=(1, 1, 1, 4), dtype=float32, numpy=
array([[[[ 1.048703  , -1.0948269 , -0.04476056, -1.7289025 ]]]],
      dtype=float32)>

채널이 4개니까 4개의 결과가 출력되었다.

cnv.weights
[<tf.Variable 'conv2d_10/kernel:0' shape=(2, 2, 1, 4) dtype=float32, numpy=
 array([[[[-0.08230966, -0.15132892, -0.12760344, -0.38952267]],
 
         [[-0.36398047,  0.07347518, -0.08780673,  0.46633136]]],
 
 
        [[[ 0.19759327, -0.46042526, -0.15406173, -0.34838456]],
 
         [[ 0.33916563, -0.08248386,  0.11705655, -0.49948823]]]],
       dtype=float32)>,
 <tf.Variable 'conv2d_10/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>]
cnv.weights[0] # (2,2) 커널의 크기 // 1은 XXX의 채널 수 // 4는 Conv(XXX)의 채널 수
<tf.Variable 'conv2d_10/kernel:0' shape=(2, 2, 1, 4) dtype=float32, numpy=
array([[[[-0.08230966, -0.15132892, -0.12760344, -0.38952267]],

        [[-0.36398047,  0.07347518, -0.08780673,  0.46633136]]],


       [[[ 0.19759327, -0.46042526, -0.15406173, -0.34838456]],

        [[ 0.33916563, -0.08248386,  0.11705655, -0.49948823]]]],
      dtype=float32)>
cnv.weights[1]
<tf.Variable 'conv2d_10/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>

이 값은 0이니 여기서는 신경쓰지 않도록 하자

cnv.weights[0][...,0].reshape(2,2) # Conv(XXX)의 첫번째 채널 출력을 얻기 위해 곱해지는 w
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[-0.08230966, -0.36398047],
       [ 0.19759327,  0.33916563]], dtype=float32)>

첫 번째 채널을 얻기 위해 나오는 계수 값

  • (2,2,1) 차원으로 나옴
tf.reduce_sum(XXX.reshape(1,2,2) * cnv.weights[0][...,0].reshape(2,2))
<tf.Tensor: shape=(), dtype=float64, numpy=1.0487029552459717>

위 결과와 같은 출력 결과

x의채널이 3개면 컬러 1개면 흑백이었지.

채널이 4개까지 커졌잖아.

채널이 원래 1개 혹은 3개가 있는데 4개?5개?50개로 키워서 relu해 ... 큰 의미가 없.....

채널을 많이 늘려서 의미있는 채널이 있을 것이라고 생각하며 키운 것일뿐!

- 계산결과를 확인하기 위해 쉽게 만든 약간의 트릭

[1]*1*2*2*1
[1, 1, 1, 1]
tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(4,(2,2))
XXX = tnp.array([1]*1*2*2*1,dtype=tf.float64).reshape(1,2,2,1)
print(XXX.reshape(1,2,2))
tf.Tensor(
[[[1. 1.]
  [1. 1.]]], shape=(1, 2, 2), dtype=float64)
  • 이렇게 XXX를 설정하면 cnv(XXX)의 결과는 단지 cnv의 weight들의 sum이 된다.
cnv(XXX)
<tf.Tensor: shape=(1, 1, 1, 4), dtype=float32, numpy=
array([[[[ 0.09046876, -0.6207629 , -0.25241536, -0.7710641 ]]]],
      dtype=float32)>

채널이 4개니까 4개의 결과가 출력되었다.

cnv.weights
[<tf.Variable 'conv2d_11/kernel:0' shape=(2, 2, 1, 4) dtype=float32, numpy=
 array([[[[-0.08230966, -0.15132892, -0.12760344, -0.38952267]],
 
         [[-0.36398047,  0.07347518, -0.08780673,  0.46633136]]],
 
 
        [[[ 0.19759327, -0.46042526, -0.15406173, -0.34838456]],
 
         [[ 0.33916563, -0.08248386,  0.11705655, -0.49948823]]]],
       dtype=float32)>,
 <tf.Variable 'conv2d_11/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>]
cnv.weights[0] # (2,2) 커널의 크기 // 1은 XXX의 채널 수 // 4는 Conv(XXX)의 채널 수
<tf.Variable 'conv2d_11/kernel:0' shape=(2, 2, 1, 4) dtype=float32, numpy=
array([[[[-0.08230966, -0.15132892, -0.12760344, -0.38952267]],

        [[-0.36398047,  0.07347518, -0.08780673,  0.46633136]]],


       [[[ 0.19759327, -0.46042526, -0.15406173, -0.34838456]],

        [[ 0.33916563, -0.08248386,  0.11705655, -0.49948823]]]],
      dtype=float32)>
cnv.weights[1]
<tf.Variable 'conv2d_11/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>

이 값은 0이니 여기서는 신경쓰지 않도록 하자

cnv.weights[0][...,0].reshape(2,2) # Conv(XXX)의 첫번째 채널 출력을 얻기 위해 곱해지는 w
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[-0.08230966, -0.36398047],
       [ 0.19759327,  0.33916563]], dtype=float32)>

첫 번째 채널을 얻기 위해 나오는 계수 값

  • (2,2,1) 차원으로 나옴
tf.reduce_sum(cnv.weights[0][...,0]),tf.reduce_sum(XXX.reshape(1,2,2) * cnv.weights[0][...,0].reshape(2,2)) # 같은 결과!
(<tf.Tensor: shape=(), dtype=float32, numpy=0.090468764>,
 <tf.Tensor: shape=(), dtype=float64, numpy=0.09046876430511475>)

테스트6

X의 채널이 여러개 있고, conv의 채널도 여러개 일때

tf.random.set_seed(43052)
cnv = tf.keras.layers.Conv2D(4,(2,2))
XXX = tnp.array([1]*1*2*2*3,dtype=tf.float64).reshape(1,2,2,3) # 채널이 3에서 4로 커지는 !
cnv(XXX)
<tf.Tensor: shape=(1, 1, 1, 4), dtype=float32, numpy=
array([[[[ 0.3297621, -0.4498347, -1.0487393, -1.580095 ]]]],
      dtype=float32)>
cnv.weights[0] ## (2,2) 는 커널의 사이즈 // 3은 XXX의 채널 // 4는 conv(XXX)의 채널
<tf.Variable 'conv2d_12/kernel:0' shape=(2, 2, 3, 4) dtype=float32, numpy=
array([[[[-0.06956434, -0.12789628, -0.10784459, -0.32920673],
         [-0.30761963,  0.06209785, -0.07421023,  0.3941219 ],
         [ 0.16699678, -0.38913035, -0.13020593, -0.29443866]],

        [[ 0.28664726, -0.0697116 ,  0.09893084, -0.4221446 ],
         [-0.23161241, -0.16410837, -0.36420006,  0.12424195],
         [-0.14245945,  0.36286396, -0.10751781,  0.1733647 ]]],


       [[[ 0.02764335,  0.15547717, -0.42024496, -0.31893867],
         [ 0.22414821,  0.3619454 , -0.00282967, -0.3503708 ],
         [ 0.4610079 , -0.17417148,  0.00401336, -0.29777044]],

        [[-0.1620284 , -0.42066965, -0.01578814, -0.4240524 ],
         [ 0.37925082,  0.24236053,  0.3949356 , -0.20996472],
         [-0.30264795, -0.28889188, -0.3237777 ,  0.37506342]]]],
      dtype=float32)>
cnv.weights[0][...,0] ## cnv(XXX)의 첫번째 채널 결과를 얻기 위해서 사용하는 w
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[-0.06956434, -0.30761963,  0.16699678],
        [ 0.28664726, -0.23161241, -0.14245945]],

       [[ 0.02764335,  0.22414821,  0.4610079 ],
        [-0.1620284 ,  0.37925082, -0.30264795]]], dtype=float32)>
tf.reduce_sum(cnv.weights[0][...,0]) # cnv(XXX)의 첫번째 채널의 결과
<tf.Tensor: shape=(), dtype=float32, numpy=0.32976213>

위와 일치하는 결과

print(tf.reduce_sum(cnv.weights[0][...,0]))
print(tf.reduce_sum(cnv.weights[0][...,1]))
print(tf.reduce_sum(cnv.weights[0][...,2]))
print(tf.reduce_sum(cnv.weights[0][...,3])) ### cnv(XXX)의 결과
tf.Tensor(0.32976213, shape=(), dtype=float32)
tf.Tensor(-0.44983464, shape=(), dtype=float32)
tf.Tensor(-1.0487392, shape=(), dtype=float32)
tf.Tensor(-1.5800952, shape=(), dtype=float32)
cnv(XXX)
<tf.Tensor: shape=(1, 1, 1, 4), dtype=float32, numpy=
array([[[[ 0.3297621, -0.4498347, -1.0487393, -1.580095 ]]]],
      dtype=float32)>

똑같이 재현된 모습

cnv.weights[0][...,0] # (2,2,3) 3은 x의 입력 채널에 대응한다.
<tf.Tensor: shape=(2, 2, 3), dtype=float32, numpy=
array([[[-0.06956434, -0.30761963,  0.16699678],
        [ 0.28664726, -0.23161241, -0.14245945]],

       [[ 0.02764335,  0.22414821,  0.4610079 ],
        [-0.1620284 ,  0.37925082, -0.30264795]]], dtype=float32)>
w_red = cnv.weights[0][...,0][...,0]
w_green = cnv.weights[0][...,0][...,1]
w_blue = cnv.weights[0][...,0][...,2]
XXX[...,0] # X_red
<tf.Tensor: shape=(1, 2, 2), dtype=float64, numpy=
array([[[1., 1.],
        [1., 1.]]])>
tf.reduce_sum(XXX[...,0] * w_red + XXX[...,1] * w_green + XXX[...,2] * w_blue) # cnv(XXX)의 첫번째 채널의 출력 결과
<tf.Tensor: shape=(), dtype=float64, numpy=0.32976213097572327>

HW

아래와 같은 흑백이미지가 있다고 하자

0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1
0 0 0 1 1 1

위의 이미지에 아래와 같은 weight를 가진 필터를 적용하여 convolution 한 결과를 계산하라.(bias는 0으로 가정한다.)

pythin
-1 1
-1 1
cnv = tf.keras.layers.Conv2D(1,(2,2))
XXX = tf.constant([[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1],[0,0,0,1,1,1]],dtype=tf.float64).reshape(1,6,6,1)
XXX.reshape(1,6,6)
<tf.Tensor: shape=(1, 6, 6), dtype=float64, numpy=
array([[[0., 0., 0., 1., 1., 1.],
        [0., 0., 0., 1., 1., 1.],
        [0., 0., 0., 1., 1., 1.],
        [0., 0., 0., 1., 1., 1.],
        [0., 0., 0., 1., 1., 1.],
        [0., 0., 0., 1., 1., 1.]]])>
cnv(XXX).reshape(1,5,5)
<tf.Tensor: shape=(1, 5, 5), dtype=float32, numpy=
array([[[0.       , 0.       , 1.4988861, 1.336632 , 1.336632 ],
        [0.       , 0.       , 1.4988861, 1.336632 , 1.336632 ],
        [0.       , 0.       , 1.4988861, 1.336632 , 1.336632 ],
        [0.       , 0.       , 1.4988861, 1.336632 , 1.336632 ],
        [0.       , 0.       , 1.4988861, 1.336632 , 1.336632 ]]],
      dtype=float32)>
cnv.weights[0]
<tf.Variable 'conv2d_13/kernel:0' shape=(2, 2, 1, 1) dtype=float32, numpy=
array([[[[-0.51669824]],

        [[ 0.6782736 ]]],


       [[[ 0.3544441 ]],

        [[ 0.8206125 ]]]], dtype=float32)>
_w = tf.constant([[-1,1],[-1,1]],dtype=tf.float64).reshape(2,2,1,1)
_b = tf.constant([0],dtype=tf.float64)x
cnv.set_weights([_w,_b])
cnv.weights
[<tf.Variable 'conv2d_13/kernel:0' shape=(2, 2, 1, 1) dtype=float32, numpy=
 array([[[[-1.]],
 
         [[ 1.]]],
 
 
        [[[-1.]],
 
         [[ 1.]]]], dtype=float32)>,
 <tf.Variable 'conv2d_13/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]
cnv(XXX).reshape(1,5,5)
<tf.Tensor: shape=(1, 5, 5), dtype=float32, numpy=
array([[[0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.],
        [0., 0., 2., 0., 0.]]], dtype=float32)>