https://school.programmers.co.kr/learn/courses/30/lessons/181187

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

※ 문제

x축과 y축으로 이루어진 2차원 직교 좌표계에 중심이 원점인 서로 다른 크기의 원이 두 개 주어집니다. 반지름을 나타내는 두 정수 r1, r2가 매개변수로 주어질 때, 두 원 사이의 공간에 x좌표와 y좌표가 모두 정수인 점의 개수를 return하도록 solution 함수를 완성해주세요.


※ 각 원 위의 점도 포함하여 셉니다.

 

※ 나의 풀이

일단 피타고라스 정리를 이용하여 접근하면 편하다.

먼저 x축과 y축에 있는 점들은 제외하고 4분면으로 나누어서 각 면에 있는 점들을 구하여 곱하기 4를 해준다.

그 후, x축과 y축에 있는 점들을 더해주면 된다!

 

	int r1 = 2, r2 = 3;
	vector<pair<int, int>> points;
	
	long long answer = 0;
	double r2y = 0, r1y = 0;
	int side = 0;
	for (int i = 1; i < r2; i++)
	{
		r2y = sqrt(pow(r2, 2) - pow(i, 2));

		if (r1 > i) r1y = sqrt(pow(r1, 2) - pow(i, 2));
		else r1y = 0;

		if (r1y - (int)r1y == 0 && r1y != 0)
			side++;

		answer += ((int)r2y - (int)r1y);
	}
	answer = (answer + side + r2 - r1 + 1) * 4;

'알고리즘 > Coding Test' 카테고리의 다른 글

광물 캐기 C++  (0) 2023.04.17
과제 진행하기 C++  (0) 2023.04.16
요격 시스템 C++  (0) 2023.04.14
추억점수 C++  (0) 2023.04.14
달리기 경주 C++  (0) 2023.04.14

https://school.programmers.co.kr/learn/courses/30/lessons/181188

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

※ 문제

A 나라가 B 나라를 침공하였습니다. B 나라의 대부분의 전략 자원은 아이기스 군사 기지에 집중되어 있기 때문에 A 나라는 B 나라의 아이기스 군사 기지에 융단폭격을 가했습니다.
A 나라의 공격에 대항하여 아이기스 군사 기지에서는 무수히 쏟아지는 폭격 미사일들을 요격하려고 합니다. 이곳에는 백발백중을 자랑하는 요격 시스템이 있지만 운용 비용이 상당하기 때문에 미사일을 최소로 사용해서 모든 폭격 미사일을 요격하려 합니다.
A 나라와 B 나라가 싸우고 있는 이 세계는 2 차원 공간으로 이루어져 있습니다. A 나라가 발사한 폭격 미사일은 x 축에 평행한 직선 형태의 모양이며 개구간을 나타내는 정수 쌍 (s, e) 형태로 표현됩니다. B 나라는 특정 x 좌표에서 y 축에 수평이 되도록 미사일을 발사하며, 발사된 미사일은 해당 x 좌표에 걸쳐있는 모든 폭격 미사일을 관통하여 한 번에 요격할 수 있습니다. 단, 개구간 (s, e)로 표현되는 폭격 미사일은 s와 e에서 발사하는 요격 미사일로는 요격할 수 없습니다. 요격 미사일은 실수인 x 좌표에서도 발사할 수 있습니다.
각 폭격 미사일의 x 좌표 범위 목록 targets이 매개변수로 주어질 때, 모든 폭격 미사일을 요격하기 위해 필요한 요격 미사일 수의 최솟값을 return 하도록 solution 함수를 완성해 주세요.

 

 

※ 나의 풀이

먼저 targets의 좌표들을 정렬 해주었습니다.

그리고 cur, next를 이용하여 문제풀이를 진행했습니다.

cur의 second 값이 next의 first 값보다 크다면, next의 위치를 + 해주었습니다.

반대로 cur의 second 값이 next의 first 값보다 작다면, 겹치는 부분이 없기 때문에 cur의 위치를 next로 변경 해주었습니다.

그리고 cnt++ 진행.

그런데 35점이 나왔다...

이유를 생각해보니

cur의 second 값이 next의 first 값보다 크다면, next의 위치를 + 해주는 상황에서

cur의 second 값이 next의 second 값보다 크다면 문제가 발생한다. cur = next를 해주지 않게 되면

예를 들어, cur = [1, 6], next = [2, 4] 가 된다면 2 ~ 6 사이에 요격을 진행하게 된다.

그런데 그 다음 오는 좌표가 [5, 7]이면 5 ~6 의 범위로 줄어들게 된다.

여기서 생각을 해보면 [2, 4]와 [5, 7]은 겹치지 않는다.

즉, cur = next를 해주어야 한다.

 

	vector<vector<int>> targets =
	{ {4, 5}, {4, 8}, {10, 14}, {11, 13}, {5, 12}, {3, 7}, {1, 4} };

	sort(targets.begin(), targets.end(), cmp);

	for (vector<int> t : targets)
	{
		cout << t[0] << " " << t[1] << endl;
	}

	int cnt = 1;
	int cur = 0;
	int next = 1;
	while (cur < targets.size() && next < targets.size())
	{
		if (targets[cur][1] > targets[next][0])
		{
			// 여기가 중요! 값 바꿔주기
			if (targets[cur][1] > targets[next][1])
				cur = next;
			next++;
		}
		else
		{
			cur = next;
			next++;
			cnt++;
		}
	}

'알고리즘 > Coding Test' 카테고리의 다른 글

과제 진행하기 C++  (0) 2023.04.16
두 원 사이의 정수쌍 C++  (0) 2023.04.14
추억점수 C++  (0) 2023.04.14
달리기 경주 C++  (0) 2023.04.14
K번째 수 C++  (0) 2022.05.19

https://school.programmers.co.kr/learn/courses/30/lessons/176963

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

※ 문제

사진들을 보며 추억에 젖어 있던 루는 사진별로 추억 점수를 매길려고 합니다. 사진 속에 나오는 인물의 그리움 점수를 모두 합산한 값이 해당 사진의 추억 점수가 됩니다. 예를 들어 사진 속 인물의 이름이 ["may", "kein", "kain"]이고 각 인물의 그리움 점수가 [5점, 10점, 1점]일 때 해당 사진의 추억 점수는 16(5 + 10 + 1)점이 됩니다. 다른 사진 속 인물의 이름이 ["kali", "mari", "don", "tony"]이고 ["kali", "mari", "don"]의 그리움 점수가 각각 [11점, 1점, 55점]]이고, "tony"는 그리움 점수가 없을 때, 이 사진의 추억 점수는 3명의 그리움 점수를 합한 67(11 + 1 + 55)점입니다.

그리워하는 사람의 이름을 담은 문자열 배열 name, 각 사람별 그리움 점수를 담은 정수 배열 yearning, 각 사진에 찍힌 인물의 이름을 담은 이차원 문자열 배열 photo가 매개변수로 주어질 때, 사진들의 추억 점수를 photo에 주어진 순서대로 배열에 담아 return하는 solution 함수를 완성해주세요.

 

※ 나의 풀이

이건 솔직히 어렵지 않았다.

각 이름별로 각자 고유의 점수가 있기 때문에 map을 이용하기로 했다.

 

	vector<string> name = { "may", "kein", "kain", "radi" };
	vector<int> point = { 5, 10, 1, 3 };
	vector<vector<string>> ar =
	{ {"may", "kein", "kain", "radi"},
	{"may", "kein", "brin", "deny"},
	{"kon", "kain", "may", "coni"} };

	// unordered_map이 map보다 빠르다고 한다.
	unordered_map<string, int> name_point;
	for (int i = 0; i < name.size(); i++)
	{
		name_point.insert(make_pair(name[i], point[i]));
	}

	vector<int> answer;
	for (int i = 0; i < ar.size(); i++)
	{
		int res = 0;
		for (int j = 0; j < ar[i].size(); j++)
		{
			res += name_point[ar[i][j]];
		}
		answer.push_back(res);
	}

'알고리즘 > Coding Test' 카테고리의 다른 글

두 원 사이의 정수쌍 C++  (0) 2023.04.14
요격 시스템 C++  (0) 2023.04.14
달리기 경주 C++  (0) 2023.04.14
K번째 수 C++  (0) 2022.05.19
소수 만들기 C++  (0) 2022.05.19

https://school.programmers.co.kr/learn/courses/30/lessons/178870

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

※ 문제

비내림차순으로 정렬된 수열이 주어질 때, 다음 조건을 만족하는 부분 수열을 찾으려고 합니다.


 - 기존 수열에서 임의의 두 인덱스의 원소와 그 사이의 원소를 모두 포함하는 부분 수열이어야 합니다.

   부분 수열의 합은 k입니다.
 - 합이 k인 부분 수열이 여러 개인 경우 길이가 짧은 수열을 찾습니다.
 - 길이가 짧은 수열이 여러 개인 경우 앞쪽(시작 인덱스가 작은)에 나오는 수열을 찾습니다.


수열을 나타내는 정수 배열 sequence와 부분 수열의 합을 나타내는 정수 k가 매개변수로 주어질 때, 위 조건을 만족하는 부분 수열의 시작 인덱스와 마지막 인덱스를 배열에 담아 return 하는 solution 함수를 완성해주세요. 이때 수열의 인덱스는 0부터 시작합니다.

 

※ 나의 풀이

먼저 주어지는 vector는 정렬되어 있으므로 굉장히 마음이 놓인다.

처음에는 DFS로 접근을 했지만, 시간초과가 발생했다.

누적합이라는 것을 알게 돼서 이용하기로 했다.

그리고 투포인트를 이용하여 값을 찾기로 했다.

 

	int l = 0, r = 0, s = 0, e = 0;
	int length = 2147000000;
	int n = sequence.size();	// 5
	int sum = sequence[0];

	while (true)
	{
		// 합이 k와 같다면 기존에 저장되어 있는 길이와 비교하여 s, e 값 업데이트
		if (sum == k)
		{
			int tmp = r - l + 1;
			if (tmp < length)
			{
				s = l;
				e = r;
				length = tmp;
			}
		}
		
		// l, r이 vector의 끝에 위치하면 break;
		if (r >= n && l >= n) break;

		// sum이 k보다 작으면 r을 오른쪽으로 옮긴다.
		// 그 반대의 경우 l을 오른쪽으로 옮긴다.
		// r < n을 해주지 않으면 r값만 +돼서 while문이 끝나지 않을 수 있다.
		if (sum <= k && r < n)
		{
			r++;
			if (r < n) sum += sequence[r];
		}
		else
		{
			if (l < n) sum -= sequence[l];
			l++;
		}
	}

https://school.programmers.co.kr/learn/courses/30/lessons/178871

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

※ 문제

얀에서는 매년 달리기 경주가 열립니다. 해설진들은 선수들이 자기 바로 앞의 선수를 추월할 때 추월한 선수의 이름을 부릅니다. 예를 들어 1등부터 3등까지 "mumu", "soe", "poe" 선수들이 순서대로 달리고 있을 때, 해설진이 "soe"선수를 불렀다면 2등인 "soe" 선수가 1등인 "mumu" 선수를 추월했다는 것입니다. 즉 "soe" 선수가 1등, "mumu" 선수가 2등으로 바뀝니다.

선수들의 이름이 1등부터 현재 등수 순서대로 담긴 문자열 배열 players와 해설진이 부른 이름을 담은 문자열 배열 callings가 매개변수로 주어질 때, 경주가 끝났을 때 선수들의 이름을 1등부터 등수 순서대로 배열에 담아 return 하는 solution 함수를 완성해주세요.

 

※ 나의 풀이

처음에는 그냥 for문을 돌려서 find 함수를 이용했지만 시간 초과가 발생했다.

생각해보니 각 Key에 맞는 등수는 중복되는 것이 없기 때문에 map을 이용하여 Key, Value를 이용하기로 했다.

그래서 map을 이용하여 바로바로 값에 접근할 수 있게 변경해주었다.

 

	vector<string> players = { "mumu", "soe", "poe", "kai", "mine" };
	vector<string> callings = { "kai", "kai", "mine", "mine" };
	int idx = -1;
	string tmp;
    
    // 이름, 등수를 이용한 map 선언
	map<string, int> name_rank;
	map<int, string> rank_name;
    
    // map 채워주기
	for (int i = 0; i < players.size(); i++)
	{
		string name = players[i];
		int rank = i + 1;
		
		name_rank.insert(make_pair(name, rank));
		rank_name.insert(make_pair(rank, name));
	}

	// callings에서 값을 꺼내와 map에 등록되어 있는 값 바꿔주기
	for (int i = 0; i < callings.size(); i++)
	{
		string call = callings[i];
		int call_rank = name_rank[call];
		string front_player = rank_name[call_rank - 1];
		
		name_rank[call]--;
		name_rank[front_player]++;

		rank_name[call_rank] = front_player;
		rank_name[call_rank - 1] = call;
	}

	vector<string> answer;
	for (int i = 1; i <= players.size(); i++)
	{
		answer.push_back(rank_name[i]);
	}

'알고리즘 > Coding Test' 카테고리의 다른 글

요격 시스템 C++  (0) 2023.04.14
추억점수 C++  (0) 2023.04.14
K번째 수 C++  (0) 2022.05.19
소수 만들기 C++  (0) 2022.05.19
음양 더하기 C++  (0) 2022.05.19

Weights 추출하기

import struct
import torch
from torchvision import models
from torchsummary import summary

if __name__ == '__main__':
    resnet18 = models.resnet18(pretrained=True)
    resnet18.to('cuda:0')
    resnet18.eval()
    summary(resnet18, (3, 224, 224))

    input = torch.ones(1, 3, 224, 224).to('cuda:0')
    out = resnet18(input)

    # Weights Extraction
    f = open('resnet18.wts', 'w')
    f.write('{}\n'.format(len(resnet18.state_dict().keys())))
    for k, v in resnet18.state_dict().items():
        print('key: {}      value: {}'.format(k, v.shape))
        vr = v.reshape(-1).cpu().numpy()
        f.write('{} {}'.format(k, len(vr)))
        for vv in vr:
            f.write(' ')
            f.write(struct.pack(">f", float(vv)).hex())
        f.write('\n')

 

 

※ Key, Value 정보

더보기

key: conv1.weight      value: torch.Size([64, 3, 7, 7])
key: bn1.weight      value: torch.Size([64])
key: bn1.bias      value: torch.Size([64])
key: bn1.running_mean      value: torch.Size([64])
key: bn1.running_var      value: torch.Size([64])
key: bn1.num_batches_tracked      value: torch.Size([])
key: layer1.0.conv1.weight      value: torch.Size([64, 64, 3, 3])
key: layer1.0.bn1.weight      value: torch.Size([64])
key: layer1.0.bn1.bias      value: torch.Size([64])
key: layer1.0.bn1.running_mean      value: torch.Size([64])
key: layer1.0.bn1.running_var      value: torch.Size([64])
key: layer1.0.bn1.num_batches_tracked      value: torch.Size([])
key: layer1.0.conv2.weight      value: torch.Size([64, 64, 3, 3])
key: layer1.0.bn2.weight      value: torch.Size([64])
key: layer1.0.bn2.bias      value: torch.Size([64])
key: layer1.0.bn2.running_mean      value: torch.Size([64])
key: layer1.0.bn2.running_var      value: torch.Size([64])
key: layer1.0.bn2.num_batches_tracked      value: torch.Size([])
key: layer1.1.conv1.weight      value: torch.Size([64, 64, 3, 3])
key: layer1.1.bn1.weight      value: torch.Size([64])
key: layer1.1.bn1.bias      value: torch.Size([64])
key: layer1.1.bn1.running_mean      value: torch.Size([64])
key: layer1.1.bn1.running_var      value: torch.Size([64])
key: layer1.1.bn1.num_batches_tracked      value: torch.Size([])
key: layer1.1.conv2.weight      value: torch.Size([64, 64, 3, 3])
key: layer1.1.bn2.weight      value: torch.Size([64])
key: layer1.1.bn2.bias      value: torch.Size([64])
key: layer1.1.bn2.running_mean      value: torch.Size([64])
key: layer1.1.bn2.running_var      value: torch.Size([64])
key: layer1.1.bn2.num_batches_tracked      value: torch.Size([])
key: layer2.0.conv1.weight      value: torch.Size([128, 64, 3, 3])
key: layer2.0.bn1.weight      value: torch.Size([128])
key: layer2.0.bn1.bias      value: torch.Size([128])
key: layer2.0.bn1.running_mean      value: torch.Size([128])
key: layer2.0.bn1.running_var      value: torch.Size([128])
key: layer2.0.bn1.num_batches_tracked      value: torch.Size([])
key: layer2.0.conv2.weight      value: torch.Size([128, 128, 3, 3])
key: layer2.0.bn2.weight      value: torch.Size([128])
key: layer2.0.bn2.bias      value: torch.Size([128])
key: layer2.0.bn2.running_mean      value: torch.Size([128])
key: layer2.0.bn2.running_var      value: torch.Size([128])
key: layer2.0.bn2.num_batches_tracked      value: torch.Size([])
key: layer2.0.downsample.0.weight      value: torch.Size([128, 64, 1, 1])
key: layer2.0.downsample.1.weight      value: torch.Size([128])
key: layer2.0.downsample.1.bias      value: torch.Size([128])
key: layer2.0.downsample.1.running_mean      value: torch.Size([128])
key: layer2.0.downsample.1.running_var      value: torch.Size([128])
key: layer2.0.downsample.1.num_batches_tracked      value: torch.Size([])
key: layer2.1.conv1.weight      value: torch.Size([128, 128, 3, 3])
key: layer2.1.bn1.weight      value: torch.Size([128])
key: layer2.1.bn1.bias      value: torch.Size([128])
key: layer2.1.bn1.running_mean      value: torch.Size([128])
key: layer2.1.bn1.running_var      value: torch.Size([128])
key: layer2.1.bn1.num_batches_tracked      value: torch.Size([])
key: layer2.1.conv2.weight      value: torch.Size([128, 128, 3, 3])
key: layer2.1.bn2.weight      value: torch.Size([128])
key: layer2.1.bn2.bias      value: torch.Size([128])
key: layer2.1.bn2.running_mean      value: torch.Size([128])
key: layer2.1.bn2.running_var      value: torch.Size([128])
key: layer2.1.bn2.num_batches_tracked      value: torch.Size([])
key: layer3.0.conv1.weight      value: torch.Size([256, 128, 3, 3])
key: layer3.0.bn1.weight      value: torch.Size([256])
key: layer3.0.bn1.bias      value: torch.Size([256])
key: layer3.0.bn1.running_mean      value: torch.Size([256])
key: layer3.0.bn1.running_var      value: torch.Size([256])
key: layer3.0.bn1.num_batches_tracked      value: torch.Size([])
key: layer3.0.conv2.weight      value: torch.Size([256, 256, 3, 3])
key: layer3.0.bn2.weight      value: torch.Size([256])
key: layer3.0.bn2.bias      value: torch.Size([256])
key: layer3.0.bn2.running_mean      value: torch.Size([256])
key: layer3.0.bn2.running_var      value: torch.Size([256])
key: layer3.0.bn2.num_batches_tracked      value: torch.Size([])
key: layer3.0.downsample.0.weight      value: torch.Size([256, 128, 1, 1])
key: layer3.0.downsample.1.weight      value: torch.Size([256])
key: layer3.0.downsample.1.bias      value: torch.Size([256])
key: layer3.0.downsample.1.running_mean      value: torch.Size([256])
key: layer3.0.downsample.1.running_var      value: torch.Size([256])
key: layer3.0.downsample.1.num_batches_tracked      value: torch.Size([])
key: layer3.1.conv1.weight      value: torch.Size([256, 256, 3, 3])
key: layer3.1.bn1.weight      value: torch.Size([256])
key: layer3.1.bn1.bias      value: torch.Size([256])
key: layer3.1.bn1.running_mean      value: torch.Size([256])
key: layer3.1.bn1.running_var      value: torch.Size([256])
key: layer3.1.bn1.num_batches_tracked      value: torch.Size([])
key: layer3.1.conv2.weight      value: torch.Size([256, 256, 3, 3])
key: layer3.1.bn2.weight      value: torch.Size([256])
key: layer3.1.bn2.bias      value: torch.Size([256])
key: layer3.1.bn2.running_mean      value: torch.Size([256])
key: layer3.1.bn2.running_var      value: torch.Size([256])
key: layer3.1.bn2.num_batches_tracked      value: torch.Size([])
key: layer4.0.conv1.weight      value: torch.Size([512, 256, 3, 3])
key: layer4.0.bn1.weight      value: torch.Size([512])
key: layer4.0.bn1.bias      value: torch.Size([512])
key: layer4.0.bn1.running_mean      value: torch.Size([512])
key: layer4.0.bn1.running_var      value: torch.Size([512])
key: layer4.0.bn1.num_batches_tracked      value: torch.Size([])
key: layer4.0.conv2.weight      value: torch.Size([512, 512, 3, 3])
key: layer4.0.bn2.weight      value: torch.Size([512])
key: layer4.0.bn2.bias      value: torch.Size([512])
key: layer4.0.bn2.running_mean      value: torch.Size([512])
key: layer4.0.bn2.running_var      value: torch.Size([512])
key: layer4.0.bn2.num_batches_tracked      value: torch.Size([])
key: layer4.0.downsample.0.weight      value: torch.Size([512, 256, 1, 1])
key: layer4.0.downsample.1.weight      value: torch.Size([512])
key: layer4.0.downsample.1.bias      value: torch.Size([512])
key: layer4.0.downsample.1.running_mean      value: torch.Size([512])
key: layer4.0.downsample.1.running_var      value: torch.Size([512])
key: layer4.0.downsample.1.num_batches_tracked      value: torch.Size([])
key: layer4.1.conv1.weight      value: torch.Size([512, 512, 3, 3])
key: layer4.1.bn1.weight      value: torch.Size([512])
key: layer4.1.bn1.bias      value: torch.Size([512])
key: layer4.1.bn1.running_mean      value: torch.Size([512])
key: layer4.1.bn1.running_var      value: torch.Size([512])
key: layer4.1.bn1.num_batches_tracked      value: torch.Size([])
key: layer4.1.conv2.weight      value: torch.Size([512, 512, 3, 3])
key: layer4.1.bn2.weight      value: torch.Size([512])
key: layer4.1.bn2.bias      value: torch.Size([512])
key: layer4.1.bn2.running_mean      value: torch.Size([512])
key: layer4.1.bn2.running_var      value: torch.Size([512])
key: layer4.1.bn2.num_batches_tracked      value: torch.Size([])
key: fc.weight      value: torch.Size([1000, 512])
key: fc.bias      value: torch.Size([1000])

 

 


TensorRT 사용하기

 

ResNet에는 Basic Block이라고 여러 Layer들로 구성되어 있는걸 사용합니다.

 

※ Basic Block TensorRT

IActivationLayer* BasicBlock(INetworkDefinition* network, std::map<std::string, Weights> weightMap, ITensor& input, int inc, int outc, int stride, std::string lname)
{
    Weights emptywts{ DataType::kFLOAT, nullptr, 0 };

    IConvolutionLayer* cv01 = network->addConvolutionNd(input, outc, DimsHW{ 3, 3 }, weightMap[lname + ".conv1.weight"], emptywts);
    assert(cv01);
    cv01->setStrideNd(DimsHW{ stride, stride });
    cv01->setPaddingNd(DimsHW{ 1, 1 });
    IScaleLayer* bn1 = addBatchNorm2d(network, weightMap, *cv01->getOutput(0), lname + ".bn1", 1e-5);
    IActivationLayer* relu1 = network->addActivation(*bn1->getOutput(0), ActivationType::kRELU);
    assert(relu1);

    IConvolutionLayer* cv02 = network->addConvolutionNd(*relu1->getOutput(0), outc, DimsHW{ 3, 3 }, weightMap[lname + ".conv2.weight"], emptywts);
    cv02->setPaddingNd(DimsHW{ 1, 1 });
    assert(cv02);
    IScaleLayer* bn2 = addBatchNorm2d(network, weightMap, *cv02->getOutput(0), lname + ".bn2", 1e-5);

    // 잔차 학습
    IElementWiseLayer* sum;
    if (inc == outc)
    {
        sum = network->addElementWise(input, *bn2->getOutput(0), ElementWiseOperation::kSUM);
    }
    else
    {
        IConvolutionLayer* cv03 = network->addConvolutionNd(*bn2->getOutput(0), outc, DimsHW(1, 1), weightMap[lname + ".downsample.0.weight", emptywts);
        cv03->setStrideNd(DimsHW{ stride, stride });
        IScaleLayer* bn3 = addBatchNorm2d(network, weightMap, *cv03->getOutput(0), lname + ".downsample.1", 1e-5);
        sum = network->addElementWise(*bn2->getOutput(0), *bn3->getOutput(0), ElementWiseOperation::kSUB);
    }

    IActivationLayer* relu2 = network->addActivation(*sum->getOutput(0), ActivationType::kRELU);
    assert(relu2);

    return relu2;
}

이렇게 반복적으로 사용하는 Layer들의 집합을 구성할때 주의해야 할 것이 있는데,

 

바로 stride와 padding 같은 Parameter 값들 입니다.

 

각 Layer 별로 규칙성 있게 사용한다면 그것에 맞게 구성해줘야 합니다.

 

ResNet의 BasicBlock의 경우

 

DownSampling이 진행되는 Basic Block이 있기 때문에 input channel과 output channel 값을 비교하여 구성해주어야 합니다.

 

 

※ Basic Block (layer1)

더보기

Sequential(
  (0): BasicBlock(
    (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace=True)
    (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
  (1): BasicBlock(
    (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    (relu): ReLU(inplace=True)
    (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  )
)

또 하나 중요한 점은 Pytorch 코드를 돌리면서 위와 같이 Layer들의 정보를 볼 수 있습니다.

 

하지만 잔차학습이 어디서 이루어 지는지는 파악할 수 없습니다.

 

그래서 직접 Data Flow를 따라 들어가며 구성되어 있는 Layer들을 파악해야 합니다.

 

Basic Block

위처럼 연산이 이루어집니다.

 

즉, Layer 요약본만 보고 진행하면 안되고 하나하나 다 들어가서 봐야 합니다.

 

 

위 사진 2장은 Layer를 보며 직접 쌓아 올렸습니다.

 

진행하면서 막히는 부분은 github를 참고하며 진행했습니다.

 

TensorRT에서 BatchNorm을 사용하려면 직접 작성해주어야 합니다.

 

공식은 아래 사진을 사용했습니다.

BatchNormalization Inference

 

이제 모델 Layer를 다 쌓아 올렸으면 Engine을 생성해주어야 합니다.

 

※ Engine 생성

    // 3. engine 생성
    if (make_engine)
    {
        std::cout << "------------ Create " << engineFileName << " Engine ------------" << std::endl;

        // Make Builder
        IBuilder* builder = createInferBuilder(gLogger);

        // Make Config
        IBuilderConfig* config = builder->createBuilderConfig();

        // Create Engine
        ICudaEngine* engine = createEngine(batch_size, builder, config, DataType::kFLOAT, engine_file_path);
        assert(engine != nullptr);

        IHostMemory* modelStream{ nullptr };
        *(&modelStream) = engine->serialize();

        // check engine file
        std::ofstream p("resnet18.engine", std::ios::binary);
        if (!p)
        {
            std::cerr << "could not open plan output file" << std::endl;
            return -1;
        }
        p.write(reinterpret_cast<const char*>(modelStream->data()), modelStream->size());

        // Destroy builder, config
        modelStream->destroy();
        builder->destroy();
        config->destroy();
    }

 

 

※ Call Engine

 

 

※ Inference

 

 

 

※ 출처

https://github.com/wang-xinyu/tensorrtx

https://github.com/yester31/TensorRT_EX

'Deep Learning > TensorRT' 카테고리의 다른 글

05. TensorRT VGG  (0) 2023.03.11
04. TensorRT Custom Layer 만들기  (0) 2022.02.14
02. TensorRT 다루기  (0) 2022.02.11
01. TensorRT 설치 및 다운로드  (0) 2022.02.11

chrono 사용

 

	// 시간 측정 시작
	system_clock::time_point start = system_clock::now();

	int result = 0;
	int plus = 0;
	for (int i = M; plus < N + 1; i)
	{
		plus += M;
		result += plus;
	}
	// 시간 측정 종료
	system_clock::time_point end = system_clock::now();

	// 시간 계산
	nanoseconds nano = end - start;
	microseconds micro = duration_cast<microseconds>(end - start);
	milliseconds mill = duration_cast<milliseconds>(end - start);
	seconds sec = duration_cast<seconds>(end - start);
	minutes min = duration_cast<minutes>(end - start);
	hours hour = duration_cast<hours>(end - start);

	cout << "걸린 시간 : " << nano.count() << " nanoseconds" << endl;
	cout << "걸린 시간 : " << micro.count() << " microseconds" << endl;
	cout << "걸린 시간 : " << mill.count() << " milliseconds" << endl;
	cout << "걸린 시간 : " << sec.count() << " seconds" << endl;
	cout << "걸린 시간 : " << min.count() << " minutes" << endl;
	cout << "걸린 시간 : " << hour.count() << " hour" << endl;

'Language > C++' 카테고리의 다른 글

C++ 시간 재기  (0) 2022.03.14
Mat 형식 Binary file로 저장 및 Binary file 불러오기  (0) 2022.02.22
opencv vector to Mat  (0) 2021.12.23
Image to Base64, Base64 to Image  (0) 2021.11.18
파일 랜덤 추출  (0) 2021.10.14

VGG 모델을 TensorRT로 포팅을 진행해보겠습니다.

 

Weights 추출하기

먼저 TensorRT 에서 모델을 사용하기 위해서는 Weights 파일을 추출해야 합니다.

 

import torch
import struct
from torchsummary import summary


def main():
    print('cuda device count: ', torch.cuda.device_count())
    net = torch.load('vgg.pth')
    net = net.to('cuda:0')
    net = net.eval()
    print('model: ', net)
    # print('state dict: ', net.state_dict().keys())
    tmp = torch.ones(1, 3, 224, 224).to('cuda:0')
    print('input: ', tmp)
    out = net(tmp)

    print('output:', out)

    summary(net, (3, 224, 224))
    # return
    f = open("vgg.wts", 'w')
    f.write("{}\n".format(len(net.state_dict().keys())))
    for k, v in net.state_dict().items():
        print('key: ', k)
        print('value: ', v.shape)
        vr = v.reshape(-1).cpu().numpy()
        f.write("{} {}".format(k, len(vr)))
        for vv in vr:
            f.write(" ")
            f.write(struct.pack(">f", float(vv)).hex())
        f.write("\n")


if __name__ == '__main__':
    main()

※ 출처 : https://github.com/wang-xinyu/pytorchx/blob/master/vgg/inference.py

 

먼저 Pytorch에서 제공하는 Pretrained VGG를 불러옵니다.

 

위 코드에서는 .pth 로 불러왔지만 실제로 테스트 할때는 torchvision.models 에서 Pretrained VGG11을 가져왔습니다.

 

TensorRT에서 사용하기 위해서 key, value로 나누어 .wts 형식으로 저장해줍니다.

 

이중 하나를 print 해보면 아래와 같습니다.

  • key:  features.0.weight
  • value:  torch.Size([64, 3, 3, 3])

또한 Value 값을 저장해 줄 때 빅라디안 방식의 float 형식, 16진수로 값을 하나씩 띄어쓰기를 기준으로 저장해줍니다.

 

 

저장되어 있는 형태를 간단히 보자면 위와 같습니다.

 

※ 22개의 key, value 정보

더보기

key:  features.0.weight   value:  torch.Size([64, 3, 3, 3])
key:  features.0.bias   value:  torch.Size([64])
key:  features.3.weight   value:  torch.Size([128, 64, 3, 3])
key:  features.3.bias   value:  torch.Size([128])
key:  features.6.weight   value:  torch.Size([256, 128, 3, 3])
key:  features.6.bias   value:  torch.Size([256])
key:  features.8.weight   value:  torch.Size([256, 256, 3, 3])
key:  features.8.bias   value:  torch.Size([256])
key:  features.11.weight   value:  torch.Size([512, 256, 3, 3])
key:  features.11.bias   value:  torch.Size([512])
key:  features.13.weight   value:  torch.Size([512, 512, 3, 3])
key:  features.13.bias   value:  torch.Size([512])
key:  features.16.weight   value:  torch.Size([512, 512, 3, 3])
key:  features.16.bias   value:  torch.Size([512])
key:  features.18.weight   value:  torch.Size([512, 512, 3, 3])
key:  features.18.bias   value:  torch.Size([512])
key:  classifier.0.weight   value:  torch.Size([4096, 25088])
key:  classifier.0.bias   value:  torch.Size([4096])
key:  classifier.3.weight   value:  torch.Size([4096, 4096])
key:  classifier.3.bias   value:  torch.Size([4096])
key:  classifier.6.weight   value:  torch.Size([1000, 4096])
key:  classifier.6.bias   value:  torch.Size([1000])

 


TensorRT 사용하기

 

이제 TensorRT를 사용해보겠습니다.

 

먼저 모델에 관련된 변수들을 선언해줍니다.

 

// 1. 변수 선언
input, output data shape
static const int INPUT_H = 224;
static const int INPUT_W = 224;
static const int INPUT_C = 3;
static const int OUTPUT_SIZE = 1000;
unsigned int batch_size = 1;		// 사용할 배치 사이즈 값

bool serialize = false;				// Engine 생성 유무, true : 엔진 생성
char engineFileName[] = "vgg11";	// Engine 이름

const char* INPUT_BLOB_NAME = "data";
const char* OUTPUT_BLOB_NAME = "prob";

char engine_file_path[256];
sprintf(engine_file_path, "../Engine/%s.engine", engineFileName);	// Engine 저장 경로
  • Input 이미지의 H, W, C
  • Output Size
  • Batch Size
  • Serialize : Engine 강제 생성 유무
  • Engine Name
  • Input Name
  • Output Name

 

// Builds an engine from a network definition.
IBuilder* builder = createInferBuilder(gLogger);

// Holds properties for configuring a builder to produce an engine.
IBuilderConfig* config = builder->createBuilderConfig();

// Create Engine
createEngine(batch_size, builder, config, DataType::kFLOAT, engine_file_path);

// Destroy builder, config
builder->destroy();
config->destroy();
  • Builder, Config : 엔진 생성을 위한 변수

엔진 생성을 위해 createEngine 함수를 만들어 줍니다.

 

// Create Engine

std::cout << "------------ Model Build Start ------------" << std::endl;
// A network definition for input to the builder.
INetworkDefinition* network = builder->createNetworkV2(0U);

// Load .wts File
// Weights : [DataType type, const void* values, int64_t count]
std::map<std::string, Weights> weightMap = loadWeights("../Weights/vgg11.wts");

// Create Input Data
ITensor* data = network->addInput(INPUT_BLOB_NAME, dt, Dims3{ INPUT_H, INPUT_W, INPUT_C });
assert(data);

// Create Model Layers
IConvolutionLayer* conv1 = network->addConvolutionNd(*data, 64, DimsHW{ 3, 3 }, weightMap["features.0.weight"], weightMap["features.0.bias"]);

...

fc1->getOutput(0)->setName(OUTPUT_BLOB_NAME);
std::cout << "set name out" << std::endl;
network->markOutput(*fc1->getOutput(0));

// Build engine
builder->setMaxBatchSize(batch_size);   // 사용할 Batch Size 설정
config->setMaxWorkspaceSize(1 << 20);   // 사용할 메모리 크기 설정

std::cout << "Building engine, please wait for a while..." << std::endl;
IHostMemory* engine = builder->buildSerializedNetwork(*network, *config);
std::cout << "==== model build done ====" << std::endl << std::endl;

std::cout << "==== model selialize start ====" << std::endl << std::endl;
std::ofstream p(engineFileName, std::ios::binary);
if (!p) {
    std::cerr << "could not open plan output file" << std::endl << std::endl;
}
p.write(reinterpret_cast<const char*>(engine->data()), engine->size());
std::cout << "==== model selialize done ====" << std::endl << std::endl;

engine->destroy();
network->destroy();
p.close();
// Release host memory
for (auto& mem : weightMap)
{
    free((void*)(mem.second.values));
}

모델 Layer는 너무 길어서 생략했습니다.

 

이제 만들거나 불러온 Engine File이 올바른지 확인을 해봅니다.

 

// 4. Engine file 로드 
char* trtModelStream{ nullptr };// 저장된 스트림을 저장할 변수
size_t size{ 0 };
std::cout << "------------ Engine file load ------------" << std::endl << std::endl;
std::ifstream file(engine_file_path, std::ios::binary);
if (file.good()) {							// good() : 입출력 가능 여부 확인
    file.seekg(0, file.end);				// seekg() : 포인터 이동
    size = file.tellg();					// tellg() : 크기
    file.seekg(0, file.beg);
    trtModelStream = new char[size];
    file.read(trtModelStream, size);
    file.close();
}
else {
    std::cout << "[ERROR] Engine file load error" << std::endl;
}

Engine File을 읽어와 trModelStream 변수에 저장시켜 주고

 

// 5. Engine File 로드 후 Engine 생성
std::cout << "------------ Engine file deserialize ------------" << std::endl << std::endl;
IRuntime* runtime = createInferRuntime(gLogger);
ICudaEngine* engine = runtime->deserializeCudaEngine(trtModelStream, size);
IExecutionContext* context = engine->createExecutionContext();
delete[] trtModelStream;

void* buffers[2];
const int inputIndex = engine->getBindingIndex(INPUT_BLOB_NAME);
const int outputIndex = engine->getBindingIndex(OUTPUT_BLOB_NAME);

// GPU에서 입력과 출력으로 사용할 메모리 공간할당
CHECK(cudaMalloc(&buffers[inputIndex], batch_size * INPUT_C * INPUT_H * INPUT_W * sizeof(uint8_t)));
CHECK(cudaMalloc(&buffers[outputIndex], batch_size * OUTPUT_SIZE * sizeof(float)));

Engine을 생성하게 됩니다.

 

이제 데이터를 넣어 연산을 진행해봅니다.

 

// 7. Inference
// CUDA 스트림 생성
cudaStream_t stream;
CHECK(cudaStreamCreate(&stream));

for (int i = 0; i < iter_count; i++) {
    auto start = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();

    CHECK(cudaMemcpyAsync(buffers[inputIndex], input.data(), batch_size * INPUT_C * INPUT_H * INPUT_W * sizeof(uint8_t), cudaMemcpyHostToDevice, stream));
    context->enqueue(batch_size, buffers, stream, nullptr);
    CHECK(cudaMemcpyAsync(outputs.data(), buffers[outputIndex], batch_size * OUTPUT_SIZE * sizeof(float), cudaMemcpyDeviceToHost, stream));
    cudaStreamSynchronize(stream);

    auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - start;
    dur_time += dur;
    std::cout << dur << " milliseconds" << std::endl;
}

먼저 GPU를 사용하기 위해 CUDA Stream을 생성해줍니다.

 

CUDA 관련 내용은 다루지 않겠습니다.

 

이제 결과를 출력해주면 끝입니다!

 

// 8. 결과 출력
int max_index = max_element(outputs.begin(), outputs.end()) - outputs.begin();

// Release stream and buffers ...
cudaStreamDestroy(stream);
CHECK(cudaFree(buffers[inputIndex]));
CHECK(cudaFree(buffers[outputIndex]));
context->destroy();
engine->destroy();
runtime->destroy();

 

 

 

 

 

 

 

 

 

※ 참고 자료 : 

https://docs.nvidia.com/deeplearning/tensorrt/api/python_api/infer/Core/Logger.html

 

https://github.com/yester31/TensorRT_EX

↑ 굉장히 잘나와있다 추천!

'Deep Learning > TensorRT' 카테고리의 다른 글

06. TensorRT Resnet18  (0) 2023.03.21
04. TensorRT Custom Layer 만들기  (0) 2022.02.14
02. TensorRT 다루기  (0) 2022.02.11
01. TensorRT 설치 및 다운로드  (0) 2022.02.11

+ Recent posts