본문 바로가기
학부생의학부연구생/_deep_learning

Convolutional layer : C로 구현 해보자! (2)

by 호상 🐧 2022. 3. 30.

무려 13일 만에 돌아온 convolutional layer : C로 구현해보자! (2) 입니다. (❁´◡`❁)

 

그동안 뭐했는지 변명아닌 변명을 하자면..... 3학년이 되니까 엄청 바빠지네요....ㅎㅎ 이것저것 할것도 많고 하는것도 많고 과제도 많고 강의도 많고.... 이게 컴공 3학년인가...? 싶습니다. 아무튼 각설하고 포스팅 시작하겠습니다.

 

 

본격적인 conv 과정을 해보자!

포스팅 (1) 에서는 이미지를 padding 하는것 까지 했다면 이제 conv 과정을 할 차례입니다. 

https://strangecat.tistory.com/50?category=998875 

 

Convolutional layer : C로 구현 해보자! (1)

학부연구생 과제로 convolutional layer 를 구현을 진행했었는데 구현한지는 꽤 되었지만 그동안 미루고 미룬탓에 지금 작성하게 된다. (⊙_⊙;) assign 에 대한 자세한 내용은 저작권이 걸려있기 때문

strangecat.tistory.com

/*이전 포스팅과 내용이 이어지니 (1) 을 먼저 읽어보세요 (●'◡'●) */

 

일단은 코드를 먼저 보시죠!

 

for (int h_out = 0; h_out < y; h_out += stride)
	{
		for (int w_out = 0; w_out < x; w_out += stride)
		{
			for (int oc = 0; oc < out_ch; oc++)
			{
				//output conv result
				float out_result = 0;

				for (int ic = 0; ic < in_ch; ic++)
				{
					for (int r = 0; r < k_size; r++)
					{
						for (int s = 0; s < k_size; s++)
						{
							//exception : pad area is no carculating
							if (
								h_out + (r-1) >= y ||
								w_out + (s-1) >= x ||
								h_out + (r-1) < 0 ||
								w_out + (s-1) < 0)
							{
								continue;
							}

							int pad_contain_index =
								((h_out + r) * (x + (pad * 2)) * in_ch) +
								((w_out + s) * in_ch) + ic;
							int weight_index =
								(oc * in_ch * k_size * k_size) +
								(ic * k_size * k_size) +
								(r * k_size) + s;


							out_result +=
								pad_contain_in[pad_contain_index] * weight[weight_index];
						}
					}
				}
                
				//insert output map
				int out_index = (h_out * x * out_ch) + (w_out * out_ch) + oc;
				output[out_index] += out_result;
			}
		}
	}

 

처음 보시면 이게 대체 무슨 코드야?! 라고 생각하실 수 있습니다.

저도 선배분들께서 힌트를 주시기 전까지는 많이 해맸거든요.... ㅠㅠ

그중에서 가장 크게 다가 왔던것은 아마 6중 포문 일것입니다.

 

이것을 이해할려면 일단 conv 과정을 이해 하셔야 하는데요.

이역시 이전 포스팅에서 많은 참고자료를 남겼기 때문에

또한 (1)을 보시고 왔을거라 생각해서 따로 다루진 않겠습니다.

 

일단 6중 포문을 사용하는 이유를 설명드리자면

for문을 하나하나 뜯어봐야겠는데요. 

 

제일 밑단의 3개의 포문은 kernel 의 이동에 영향을 줍니다.

본 구현의 kernel 은

 

output_chenel : 16

input_chenel : 3

k_size : 3

 

이고, 해당 for문의 역할은

 

위의 그림처럼 이동하도록 되있습니다.

왜냐하면 커널을 구성할때 n , k , r , s 순으로 구성하였고, 따라서 위에 그림처럼 접근한다는것을 알 수 있죠.

 

커널의 이동을 설명 드렸다면 다음 포문으로 넘어가죠.

 

위 포문을 보면 out_ch 별로 out_result 를 설정 해주었습니다.

 

예를 들어 input 의 인덱스가 0 을 시작으로 conv 를 진행해 줄 것입니다.

그럼 커널 사이즈에 맞게 

위처럼 위치한 pixel 의 value값에 같은 위치인 커널의 weight 를 곱해주고 

9개의 값을 더해준것이 output_feature map 의 index 0의 자리의 값이 되겠죠?

 

이것을 output chenel에 따라 삽입하는 과정을 진행 하였습니다.

즉 H W C 방식으로 삽입했다고 할 수 있네요.

 좀 더 이해 쉽게 설명 하자면 파란색 화살표에 따라 conv 과정을 진행 한 것 입니다.

따라서 output index 0에 위치하고 그 위치의 ch 만큼 conv 과정을 한것이죠.

 

한칸당 16개 들어가는  가로 256 세로 256 칸인 신발장에

왼쪽 위부터 신발을 넣었다고 할 수 있겠네요.

 

결국 위에 for문은 신발장을 왼쪽부터 오른쪽으로

위에서 아래로 이동해 주는 역할을 하게 됩니다. 

 

그래서 이렇게 6중 for문을 구성하게 된답니다....(❁´◡`❁)

 

이 for문의 구성만 이해 하셨다면 다른건 이제 껌 입니다. ㅎㅎ

if 문은 index 를 벗어나는것을 방지하기 위한 exception 이고

input , weight index를 설정해주시고 conv 를 진행해 주시면 됩니다. 

 

conv 를 진행한 out_result 는 

 

ic for 문이 끝날때 삽입 해주면 끝!

 

참 쉽죠?

 

이렇게 해서 convolutional layer : C로 구현해보자! 가 끝이 납니다.

 

좀 싱겁게 끝낸 감이 없지않아 있습니다만,

한낱 학부연구생의 포스팅이므로

도움이 되셨다면 다행이고, 안되셨다면 긴글을 읽어주신것에 감사드리고 죄송합니다 (┬┬﹏┬┬)

 

본 구현의 전체적인 코드는 제 git에 올려놓았습니다.

https://github.com/rofe12/CNN/blob/master/Convolution%20Layer/Convolution_Layer.c

 

GitHub - sangho0804/CNN: for deep Learning CNN study

for deep Learning CNN study. Contribute to sangho0804/CNN development by creating an account on GitHub.

github.com

댓글