<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hang_geee.log</title>
        <link>https://velog.io/</link>
        <description>매일 조금씩 성장하는 개발자</description>
        <lastBuildDate>Wed, 25 Jan 2023 04:22:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hang_geee.log</title>
            <url>https://velog.velcdn.com/images/hang_geee/profile/ee65e59a-85df-441f-b352-d96c67939506/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hang_geee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hang_geee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[C언어] scanf와 scanf_s 차이]]></title>
            <link>https://velog.io/@hang_geee/C%EC%96%B8%EC%96%B4-scanf-scanfs-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@hang_geee/C%EC%96%B8%EC%96%B4-scanf-scanfs-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Wed, 25 Jan 2023 04:22:17 GMT</pubDate>
            <description><![CDATA[<p>C언어에 대한 입문을 시작했다.</p>
<p>근본 없이 공부를 이어나갈 수 없으니 빠르게라도 한 번 훑고 컴퓨터구조나 자료 구조에 대해서 공부하면 좋을 것 같다!</p>
<p>python을 먼저 배웠기 때문에 변수가 무엇이고 상수가 무엇이고 입출력이 무엇인지는 알고 있었는데 scanf와 scanf_s 차이가 궁금해서 적게 되었다.</p>
<p>visual studio code를 이용해서 책을 보며 따라하고 있었는데</p>
<p>책 예제에 scanf_s가 있는 그대로 치니 실행이 되지 않고 scanf를 치니 되었다.</p>
<p>차이가 무엇일까?</p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/5ee1ed8c-7954-4105-ac8f-2fb39e81c51c/image.png" alt=""></p>
<h3 id="did-you-mean-scanf">did you mean &#39;scanf&#39;?</h3>
<p>scanf는 아는 것 같은데.. visual studio code라서 scanf_s를 모르는 건가? 싶어서 여기저기 찾아보았다. 나도 사실 뭔지 몰라서</p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/f7f1369d-7b05-4628-9866-7818354ce2c8/image.png" alt=""></p>
<h2 id="끝">끝?</h2>
<p>다른 블로그를 더 찾아보니</p>
<p>scanf_s는 오버플로우 방지가 가능하다고 한다.</p>
<p>int, float, double 같은 자료형은 자료형 크기가 일정하기 때문에 자료형을 입력받는데 문제가 없지만,</p>
<p>char, char[]형태인 문자, 문자열에서는 입력받을 크기를 반드시 뒤에 입력해주어야 합니다.</p>
<p>scanf_s(&quot;%s&quot;, 문자열변수명, sizeof(문자열변수명)); 을 써주면 입력 받을 수 있다고 한다.</p>
<h2 id="결론">결론</h2>
<ul>
<li>기본으로 사용하는 표준 입력 명령어는 scanf() 함수</li>
<li>but, scanf() 함수를 사용하면 입력 크기에 제한이 없어서 지정된 크기보다 더 많은 양을 입력받는 버퍼 오버플로(buffer overflow)라는 메모리 문제가 발생할 수 있다.</li>
<li>그래서 이 점을 보완해 visual studio에서 사용할 수 있도록 새로 만든 명령어가 scanf_s() 함수</li>
<li>크기를 지정한다는 것 외에 둘은 다른 점이 없고 사용법도 거의 같다!!</li>
</ul>
<h2 id="visual-studio를-쓸-거면-scanf_s를-써라">Visual Studio를 쓸 거면 scanf_s를 써라~!</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Operation System] Process & Thread]]></title>
            <link>https://velog.io/@hang_geee/Operation-System-Process-Thread</link>
            <guid>https://velog.io/@hang_geee/Operation-System-Process-Thread</guid>
            <pubDate>Fri, 21 Oct 2022 04:36:34 GMT</pubDate>
            <description><![CDATA[<p>10월 20일 진행했던 Process &amp; Thread 세미나 발표 자료</p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/9c84df8a-0ab7-4423-9fd3-ec4ae75dc52f/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/c3f2a15c-64d7-40da-a32f-11924ab71314/image.png" alt=""><img src="https://velog.velcdn.com/images/hang_geee/post/d804eff6-feef-4b2d-a908-24ac4f9d3fbd/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/4b1c2c27-6fba-4b14-9142-b5b2c09f853f/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/a53f31e1-a910-4f43-87de-1440c2b8aa32/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/6e6f571f-46d1-4e77-bb31-ae8da06bd7cd/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/ab11f96d-b2f3-4c90-b3dc-f78e14d587f0/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/711e48e1-0f3b-4300-87b2-4ff4702eee9f/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/14e43e0b-35c6-4be4-a42f-51098e47769a/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/aebb10af-9284-4e62-aa7c-6f1ddf4f0975/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/88bd6b10-de5b-45e9-b11a-6b4ea86899dc/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/dba5f730-56ec-4c92-ae70-c511bffe5784/image.png" alt="">
<img src="https://velog.velcdn.com/images/hang_geee/post/ef7f5304-8ac4-4079-af5f-7e7727b94e43/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch] 이미지 분류기 구현 - PyTorch Sequential API]]></title>
            <link>https://velog.io/@hang_geee/Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-PyTorch-Sequential-API</link>
            <guid>https://velog.io/@hang_geee/Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-PyTorch-Sequential-API</guid>
            <pubDate>Sun, 04 Sep 2022 13:45:05 GMT</pubDate>
            <description><![CDATA[<h2 id="pytorch-sequential-api">PyTorch Sequential API</h2>
<p>Feed forward layers가 여러개 쌓여져 있는 간단한 모델의 경우에도 다음과 같이 3가지 step을 따라야 합니다: subclass nn.Module, assign layers to class attributes in <strong>init</strong>, and call each layer one by one in forward(). 본 파트에서는 이보다 더 간단한 방법을 제공합니다.</p>
<p>PyTorch 는 nn.Sequential라는 container Module을 제공하고, 이는 위의 3가지 step을 하나로 합쳐 줍니다.</p>
<p>Sequential API: Two-Layer Network
먼저 nn.Sequential를 사용하여 two-layer 네트워크를 다시 정의하고, 앞서 정의한 학습 loop로 학습시켜 봅니다.</p>
<p>별도로 hyperparameters를 수정하지 않고도 한 에폭 이후 40% 이상의 분류 정확도를 보이면 성공입니다.</p>
<pre><code class="language-python"># We need to wrap `flatten` function in a module in order to stack it
# in nn.Sequential
class Flatten(nn.Module):
    def forward(self, x):
        return flatten(x)

hidden_layer_size = 4000
learning_rate = 1e-2

model = nn.Sequential(
    Flatten(),
    nn.Linear(3 * 32 * 32, hidden_layer_size),
    nn.ReLU(),
    nn.Linear(hidden_layer_size, 10),
)

# you can use Nesterov momentum in optim.SGD
optimizer = optim.SGD(model.parameters(), lr=learning_rate,
                     momentum=0.9, nesterov=True)

train_part34(model, optimizer)</code></pre>
<h3 id="sequential-api-three-layer-convnet">Sequential API: Three-Layer ConvNet</h3>
<p>이제 nn.Sequential를 활용하여 Part III와 동일한 구조의 three-layer ConvNet를 직접 정의하고 학습시켜 봅니다:</p>
<p>Convolutional layer (with bias) with 32 5x5 filters, with zero-padding of 2
ReLU
Convolutional layer (with bias) with 16 3x3 filters, with zero-padding of 1
ReLU
Fully-connected layer (with bias) to compute scores for 10 classes
Weight matrices는 앞서 정의한 random_weight 함수로 초기화 하고 bias vectors zero_weight 함수로 초기화 합니다.</p>
<p>Optimizer로는 Nesterov momentum 0.9를 갖는 stochastic gradient descent를 사용합니다.</p>
<p>별도로 hyperparameters를 수정하지 않고도 한 에폭 이후 55% 이상의 분류 정확도를 보이면 성공입니다.</p>
<pre><code class="language-python"># Req. 1-8    ThreeLayerConvNet을 Sequential API로 구현하기

channel_1 = 32
channel_2 = 16
learning_rate = 1e-2

model = None
optimizer = None

################################################################################
# TODO: Rewrite the 3-layer ConvNet with bias from Part III with the           #
# Sequential API.                                                              #
################################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

model=nn.Sequential(
    nn.Conv2d(3,channel_1,5,padding=2),
    nn.ReLU(),
    nn.Conv2d(channel_1,channel_2,3,padding=1),
    nn.ReLU(),
    Flatten(),
    nn.Linear(channel_2*32*32,10)
)
# for i in model.parameters():
    # nn.init.kaiming_normal_(i)
for i in model.modules():
    if isinstance(i,nn.Conv2d):
        i.weight=nn.Parameter(random_weight(i.weight.shape))
        i.bias=nn.Parameter(zero_weight(i.bias.shape))
optimizer=optim.SGD(model.parameters(),lr=learning_rate,momentum=0.9)

# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
################################################################################
#                                 END OF YOUR CODE                             
################################################################################

train_part34(model, optimizer)</code></pre>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/c7d4141a-ff64-4657-811f-3c90fc81d312/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch] 이미지 분류기 구현 - PyTorch Module API]]></title>
            <link>https://velog.io/@hang_geee/Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-PyTorch-Module-API</link>
            <guid>https://velog.io/@hang_geee/Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-PyTorch-Module-API</guid>
            <pubDate>Sun, 04 Sep 2022 13:23:35 GMT</pubDate>
            <description><![CDATA[<h2 id="pytorch-module-api">PyTorch Module API</h2>
<p>Barebone PyTorch에서는 모든 파라미터 텐서들을 직접 관리했습니다. 작은 네트워크일 경우일때는 괜찮지만, 네트워크가 커질수록 직접 파라미터 하나하나 정의하고 관리하기에는 불가능합니다.</p>
<p>PyTorch는 nn.Module API를 제공하여 직접 임의의 네트워크를 정의할 수 있고 학습 가능한 파라미터를 자동으로 추적할 수 있게 도와줍니다. Part II에서는 SGD를 직접 구현했지만 PyTorch는 torch.optim 패키지를 제공하여 SGD와 더불어 다양한 optimizer를 사용할수 있게 합니다. 다음의 자료 doc를 참고하여 다양한 optimizer의 정의를 살펴보길 바랍니다.</p>
<p>Module API를 사용하기 위해서 아래의 step을 따라야 합니다:</p>
<ol>
<li><p>Subclass nn.Module. nn.Module를 상속받아 TwoLayerFC와 같은 직관적인 이름으로 네트워크 클래스 정의.</p>
</li>
<li><p>정의한 클래스의 <strong>init</strong>()에서 모델을 구성하는 모든 레이어에 대해서 정의합니다. nn.Linear와 nn.Conv2d는 nn.Module의 subclasses로 학습 가능한 파라미터를 포함하고 있어 별도로 Tensor를 초기화하지 않아도 됩니다. 다양한 builtin 레이어들에 대해 공부하고 싶다면 다음 자료 doc를 참고시길 바랍니다. Warning: 클래스 정의시 super().<strong>init</strong>()를 가장 먼저 호출합니다.</p>
</li>
<li><p>forward() method에서는 네트워크 내 레이어들의 연결들을 정의해주어야 합니다. 앞선 <strong>init</strong>에서 정의한 레이어들을 입력과 출력 shape에 맞는 레이어들로 연결해줍니다. forward()에서는 새로운 학습 가능한 파라미터를 생성하면 안됩니다. 모든 파라미터 생성은 <strong>init</strong>에서 만들어져야 합니다.</p>
</li>
</ol>
<p>Module API: Two-Layer Network
아래는 2개의 레이어를 갖는 fully-connected 네트워크의 구체적인 예시입니다.</p>
<pre><code class="language-python">class TwoLayerFC(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super().__init__()
        # 레이어 2개를 정의합니다.
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, num_classes)

        # nn.init 패키지 내에서 초기화 함수를 사용합니다.
        # http://pytorch.org/docs/master/nn.html#torch-nn-init 
        nn.init.kaiming_normal_(self.fc1.weight)
        nn.init.kaiming_normal_(self.fc2.weight)

    def forward(self, x):
        # forward 에서는 레이어의 연결을 정의합니다.
        x = flatten(x)
        scores = self.fc2(F.relu(self.fc1(x)))
        return scores

def test_TwoLayerFC():
    input_size = 50
    x = torch.zeros((64, input_size), dtype=dtype)  # minibatch size 64, feature dimension 50
    model = TwoLayerFC(input_size, 42, 10)
    scores = model(x)
    print(scores.size())  # you should see [64, 10]

test_TwoLayerFC()</code></pre>
<h3 id="module-api-three-layer-convnet">Module API: Three-Layer ConvNet</h3>
<p>이제 여기서는 3개의 컨볼루션 레이어와 fully-connected 레이어를 갖는 ConvNet를 직접 구현해 봅니다. 네트워크의 구조는 Part II에서 정의한 것과 동일합니다:</p>
<p>Convolutional layer with channel_1 5x5 filters with zero-padding of 2
ReLU
Convolutional layer with channel_2 3x3 filters with zero-padding of 1
ReLU
Fully-connected layer to num_classes classes
Kaiming normal initialization method를 활용하여 정의한 레이어들을 초기화 합니다.</p>
<p>HINT: <a href="http://pytorch.org/docs/stable/nn.html#conv2d">http://pytorch.org/docs/stable/nn.html#conv2d</a></p>
<p>ConvNet를 구현한 이후, test_ThreeLayerConvNet 함수를 실행하면(64, 10) shape 의 output score를 출력하게 됩니다.</p>
<p>Pytorch functions
nn.Conv2d : torch.nn.Conv2d(in_channels: int, out_channels: int, kernel_size, stride = 1, padding = 0)
nn.Maxpool2d : torch.nn.MaxPool2d(kernel_size, stride = None, padding = 0)
nn.Linear : torch.nn.Linear(in_features: int, out_features: int, bias: bool = True)
references</p>
<p><a href="https://tutorials.pytorch.kr/beginner/examples_nn/two_layer_net_module.html">https://tutorials.pytorch.kr/beginner/examples_nn/two_layer_net_module.html</a></p>
<p><a href="https://pytorch.org/docs/stable/generated/torch.nn.MaxPool2d.html">https://pytorch.org/docs/stable/generated/torch.nn.MaxPool2d.html</a></p>
<p><a href="https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html">https://pytorch.org/docs/stable/generated/torch.nn.Conv2d.html</a></p>
<p><a href="https://pytorch.org/docs/stable/generated/torch.nn.Linear.html">https://pytorch.org/docs/stable/generated/torch.nn.Linear.html</a></p>
<p>tips</p>
<p><a href="http://taewan.kim/post/cnn/">http://taewan.kim/post/cnn/</a></p>
<p><a href="http://taewan.kim/post/cnn/#4-cnn-%EC%9E%85%EC%B6%9C%EB%A0%A5-%ED%8C%8C%EB%A6%AC%EB%AF%B8%ED%84%B0-%EA%B3%84%EC%82%B0">http://taewan.kim/post/cnn/#4-cnn-%EC%9E%85%EC%B6%9C%EB%A0%A5-%ED%8C%8C%EB%A6%AC%EB%AF%B8%ED%84%B0-%EA%B3%84%EC%82%B0</a></p>
<p><a href="https://mrsyee.github.io/image%20processing/2018/11/28/cnn_technique/">https://mrsyee.github.io/image%20processing/2018/11/28/cnn_technique/</a></p>
<pre><code class="language-python"># Req. 1-4    Three-Layer ConvNet 클래스를 Module API를 활용하여 정의하기

class ThreeLayerConvNet(nn.Module):
    def __init__(self, in_channel, channel_1, channel_2, num_classes):
        super().__init__()
        ########################################################################
        # TODO: Set up the layers you need for a three-layer ConvNet with the  #
        # architecture defined above.                                          #
        ########################################################################
        # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

        self.conv1=nn.Conv2d(in_channel,channel_1,[5,5],padding=2)
        nn.init.kaiming_normal_(self.conv1.weight)
        self.conv2=nn.Conv2d(channel_1,channel_2,[3,3],padding=1)
        nn.init.kaiming_normal_(self.conv2.weight)
        self.fc=nn.Linear(channel_2*32*32,num_classes)
        nn.init.kaiming_normal_(self.fc.weight)

        # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
        ########################################################################
        #                          END OF YOUR CODE                            #       
        ########################################################################

    def forward(self, x):
        scores = None
        ########################################################################
        # TODO: Implement the forward function for a 3-layer ConvNet. you      #
        # should use the layers you defined in __init__ and specify the        #
        # connectivity of those layers in forward()                            #
        ########################################################################
        # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

        x1=self.conv1(x)
        r1=nn.functional.relu(x1)
        x2=self.conv2(r1)
        r2=nn.functional.relu(x2)
        scores=self.fc(r2.view([-1,np.prod(r2.shape[1:])]))

        # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
        ########################################################################
        #                             END OF YOUR CODE                         #
        ########################################################################
        return scores


def test_ThreeLayerConvNet():
    x = torch.zeros((64, 3, 32, 32), dtype=dtype)  # minibatch size 64, image size [3, 32, 32]
    model = ThreeLayerConvNet(in_channel=3, channel_1=12, channel_2=8, num_classes=10)
    scores = model(x)
    print(scores.size())  # you should see [64, 10]
test_ThreeLayerConvNet()</code></pre>
<h3 id="module-api-check-accuracy">Module API: Check Accuracy</h3>
<p>Validation이나 test set이 주어졌을 때 분류 정확도를 측정합니다.</p>
<p>해당 버전은 수동으로 파라미터를 전달했던 part II와는 약간 다릅니다.</p>
<pre><code class="language-python"># Req. 1-5    Module API에서 성능 평가 함수 구현하기

def check_accuracy_part34(loader, model):
    if loader.dataset.train:
        print(&#39;Checking accuracy on validation set&#39;)
    else:
        print(&#39;Checking accuracy on test set&#39;)   
    num_correct = 0
    num_samples = 0
    model.eval()  # set model to evaluation mode

    ########################################################################
    # TODO: Implement the function for evaluating the accuracy of the model#
    ########################################################################
    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    with torch.no_grad():
        for x, y in loader:
            x = x.to(device=device, dtype=dtype)  # move to device, e.g. GPU
            y = y.to(device=device, dtype=torch.long)
            scores = model(x)
            _, preds = scores.max(1)
            num_correct += (preds == y).sum()
            num_samples += preds.size(0)
        acc = float(num_correct) / num_samples
        print(&#39;Got %d / %d correct (%.2f)&#39; % (num_correct, num_samples, 100 * acc))

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
    ########################################################################
    #                          END OF YOUR CODE                            #       
    ########################################################################</code></pre>
<h3 id="module-api-training-loop">Module API: Training Loop</h3>
<p>학습 loop를 작성합니다. 직접 파라미터를 업데이트하기 위한 코드를 작성하지 않고, torch.optim 패키지 내의 optimizer를 사용하여 자동으로 파라미터를 업데이트 해줍니다.</p>
<pre><code class="language-python"># Req. 1-6    Module API에서 학습 loop 구현하기

def train_part34(model, optimizer, epochs=1):
    &quot;&quot;&quot;
    Train a model on CIFAR-10 using the PyTorch Module API.

    Inputs:
    - model: A PyTorch Module giving the model to train.
    - optimizer: An Optimizer object we will use to train the model
    - epochs: (Optional) A Python integer giving the number of epochs to train for

    Returns: Nothing, but prints model accuracies during training.
    &quot;&quot;&quot;
    model = model.to(device=device)  # move the model parameters to CPU/GPU
    ########################################################################
    # TODO: Implement the training loop                                    #
    ########################################################################
    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
    for e in range(epochs):
        for t, (x, y) in enumerate(loader_train):
            model.train()  # put model to training mode
            x = x.to(device=device, dtype=dtype)  # move to device, e.g. GPU
            y = y.to(device=device, dtype=torch.long)

            scores = model(x)
            loss = F.cross_entropy(scores, y)

            # Zero out all of the gradients for the variables which the optimizer
            # will update.
            optimizer.zero_grad()

            # This is the backwards pass: compute the gradient of the loss with
            # respect to each  parameter of the model.
            loss.backward()

            # Actually update the parameters of the model using the gradients
            # computed by the backwards pass.
            optimizer.step()

            if t % print_every == 0:
                print(&#39;Iteration %d, loss = %.4f&#39; % (t, loss.item()))
                check_accuracy_part34(loader_val, model)
                print()

    # 1) 첫번째 for문으로 epochs 만큼 반복
    # 2) 두번째 for문으로 trainset이 저장되어 있는 loader_train에서 배치 사이즈 만큼씩 data load
    # 3) load한 data에서 input 값과 label을 device에 올림 (GPU or CPU)
    # 4) model에 input값을 입력하여 forward 패스 수행
    # 5) loss function으로 예측값과 label 비교
    # 6) optimizer에서 gradient 값 0으로 초기화
    # 7) loss 값 backpropagation 하여 gradient 계산
    # 8) Optimizer 업데이트
    # 9) loss와 accuracy를 print_every 주기 마다 출력
    # 10) 2)로 돌아가 반복 한뒤 2)가 모두 마치면 1)로 돌아가 반복

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
    ########################################################################
    #                          END OF YOUR CODE                            #       
    ########################################################################</code></pre>
<h3 id="module-api-train-a-two-layer-network">Module API: Train a Two-Layer Network</h3>
<p>이제 학습 loop 실행을 시작합니다. Part II와 다르게 파라미터를 직접 정의하지 않아도 됩니다.</p>
<p>Input size, hidden 레이어 size, output size(클래스 개수)를 입력하여 TwoLayerFC의 객체를 생성합니다.</p>
<p>또한 TwoLayerFC의 학습 가능한 파라미터를 추적하기 위한 optimizer 또한 정의합니다.</p>
<p>별도로 hyperparameters를 수정하지 않고도 한 에폭 이후 40% 이상의 분류 정확도를 보이면 성공입니다.</p>
<pre><code class="language-python">hidden_layer_size = 4000
learning_rate = 1e-2
model = TwoLayerFC(3 * 32 * 32, hidden_layer_size, 10)
optimizer = optim.SGD(model.parameters(), lr=learning_rate)

train_part34(model, optimizer)</code></pre>
<h3 id="module-api-train-a-three-layer-convnet">Module API: Train a Three-Layer ConvNet</h3>
<p>이제 Module API를 사용하여 직접 three-layer ConvNet을 설계합니다. 앞선 two-layer 네트워크와 비슷할 것 입니다. 별도로 hyperparameters를 수정하지 않고도 한 에폭 이후 40% 이상의 분류 정확도를 보이면 성공입니다. 모델 학습 시 stochastic gradient descent를 사용합니다.</p>
<pre><code class="language-python"># Req. 1-7    ThreeLayerConvNet의 instance만들고 optimizer 정의

learning_rate = 3e-3
channel_1 = 32
channel_2 = 16

model = None
optimizer = None
################################################################################
# TODO: Instantiate your ThreeLayerConvNet model and a corresponding optimizer #
################################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

model=ThreeLayerConvNet(3,channel_1,channel_2,10)
optimizer=optim.SGD(model.parameters(),lr=learning_rate)

# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
################################################################################
#                                 END OF YOUR CODE                             
################################################################################

train_part34(model, optimizer)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch] 이미지 분류기 구현 - Barebones PyTorch]]></title>
            <link>https://velog.io/@hang_geee/Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-Barebones-PyTorch</link>
            <guid>https://velog.io/@hang_geee/Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-Barebones-PyTorch</guid>
            <pubDate>Sun, 04 Sep 2022 07:09:30 GMT</pubDate>
            <description><![CDATA[<h2 id="barebones-pytorch">Barebones PyTorch</h2>
<p>PyTorch는 모델 아키텍처를 편리하게 정의할 수 있도록 high-level API와 함께 제공합니다. 본 파트에서는 high-level API를 다루기 전에 barebone PyTorch 부터 시작하여 autograd 엔진을 더 잘 이해할 수 있도록 합니다.</p>
<p>우리는 CIFAR-10 분류를 위해 두 개의 레이어와 ReLU로 구성된 간단한 fully-connected 네트워크로 시작합니다. 본 실습에서는 PyTorch Tensor의 연산을 사용하여 forward 패스를 계산하고 PyTorch autograd를 사용하여 backward 패스의 그레이디언트를 계산합니다.</p>
<p>requires_grad=True로 PyTorch Tensor를 생성하면 해당 텐서는 단순히 값을 계산하는 연산만 하는 것이 아니라 백그라운드에서 계산 그래프를 구축하여 loss와 관련된 텐서의 그레이디언트 계산합니다. 구체적으로, 만약 x가 x.requires_grad == True인 Tensor라면, 역전파 후 x.grad는 마지막에 스칼라 loss값과 관련하여 x의 그레디언트를 기록하는 또 다른 Tensor가 됩니다.</p>
<h3 id="pytorch-tensors-flatten-함수">PyTorch Tensors: Flatten 함수</h3>
<p>PyTorch Tensor는 numpy array와 유사합니다. numpy와 마찬가지로 PyTorch에서도 효율적인 Tensor 연산을 위해 많은 함수들을 제공합니다. 간단한 예로, fully-connected 네트워크에 이미지 입력을 위하여 이미지 데이터를 reshape하는 flatten 함수를 제공합니다.</p>
<p>이미지 데이터는 일반적으로 N x C x H x W 형태의 Tensor로 저장됩니다. 여기서,</p>
<p>N is the number of datapoints
C is the number of channels
H is the height of the intermediate feature map in pixels
W is the width of the intermediate feature map in pixels</p>
<p>위의 Tensor 형태의 경우, 2D 컨볼루션과 같은 공간적 이해를 필요로 하는 레이어를 적용할때 적절한 데이터 형태 입니다. 그러나 fully-connected 네트워크를 사용하여 이미지 데이터를 처리할 때 각 데이터가 단일 벡터로 표현되어야 합니다. 따라서 데이터 당 C x H x W값을 하나의 긴 벡터 형태로 변환해주기 위해 &quot;flatten&quot; 연산을 사용합니다. &quot;flatten&quot; 함수는 먼저 주어진 데이터 배치에서 N, C, H 및 W 값을 읽은 다음 해당 데이터의 &quot;view&quot;를 반환합니다. &quot;view&quot;는 numpy의 &quot;reshape&quot; 방법과 유사합니다.</p>
<pre><code class="language-python">def flatten(x):
    N = x.shape[0] # read in N, C, H, W
    return x.view(N, -1)  # &quot;flatten&quot; the C * H * W values into a single vector per image

def test_flatten():
    x = torch.arange(12).view(2, 1, 3, 2)
    print(&#39;Before flattening: &#39;, x)
    print(&#39;After flattening: &#39;, flatten(x))

test_flatten()</code></pre>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/48f6f5a2-dc51-4bc4-8175-50547d19739f/image.png" alt=""></p>
<h3 id="barebones-pytorch-two-layer-network">Barebones PyTorch: Two-Layer Network</h3>
<p>Forward 패스를 수행하는 두개의 레이어를 가진 fully-connected ReLU 모델을 two_layer_fc의 이름으로 정의합니다. 정의한 이후 모델이 잘 동작하는지 확인하기 위해 zeros 값을 넣어봅니다. 본 실습에서는 별도로 코드를 작성하진 않지만, 구현된 코드를 자세히 읽어보고 다 이해하도록 합니다.</p>
<pre><code class="language-python">import torch.nn.functional as F  # useful stateless functions

def two_layer_fc(x, params):
    &quot;&quot;&quot;
    Fully-connected 네트워크는 다음과 같이 구성되어 있습니다:
    fully connected -&gt; ReLU -&gt; fully connected layer.
    위의 정의는 forward 패스만 구현한 것이고, backward 패스는 PyTorch가 자동으로 구현합니다.

    Inputs:
    - x: A PyTorch Tensor of shape (N, d1, ..., dM) giving a minibatch of
      input data.
    - params: A list [w1, w2] of PyTorch Tensors giving weights for the network;
      w1 has shape (D, H) and w2 has shape (H, C).

    Returns:
    - scores: A PyTorch Tensor of shape (N, C) giving classification scores for
      the input data x.
    &quot;&quot;&quot;
    # 먼저 이미지를 flatten 합니다.
    x = flatten(x)  # shape: [batch_size, C x H x W]

    w1, w2 = params

    # Forward 패스: Tensor에 정의된 operation을 활용하여 y값을 예측합니다.
    # w1과 w2는 requires_grad=True로 되어 있기 때문에 자동으로 계산 그래프를 구축하여
    # 자동으로 gradient값을 계산할 수 있습니다. 
    # 따라서 수동으로 backward 패스를 구현하지 않아도 됩니다.

    x = F.relu(x.mm(w1))
    x = x.mm(w2)
    return x


def two_layer_fc_test():
    hidden_layer_size = 42
    x = torch.zeros((64, 50), dtype=dtype)  # minibatch size 64, feature dimension 50

    # weight값 초기화
    w1 = torch.zeros((50, hidden_layer_size), dtype=dtype, requires_grad=True)
    w2 = torch.zeros((hidden_layer_size, 10), dtype=dtype, requires_grad=True)

    scores = two_layer_fc(x, [w1, w2])
    print(scores.size())  # you should see [64, 10]

two_layer_fc_test()</code></pre>
<h3 id="barebones-pytorch-three-layer-convnet">Barebones PyTorch: Three-Layer ConvNet</h3>
<p>Forward 패스를 수행하는 세개의 컨볼루션 레이어를 가진 모델을 three_layer_convnet의 이름으로 정의합니다. 앞선 실습과 마찬가지로 정의한 모델이 잘 동작하는 지 확인하기 위해 zero 값을 넣어봅니다. 네트워크 아키텍쳐는 다음과 같아야 합니다.</p>
<p>A convolutional layer (with bias) with channel_1 filters, each with shape KW1 x KH1, and zero-padding of two ReLU nonlinearity
A convolutional layer (with bias) with channel_2 filters, each with shape KW2 x KH2, and zero-padding of one ReLU nonlinearity
Fully-connected layer with bias, producing scores for C classes.
본 실습에서는 마지막 fully-connected layer 이후에 softmax activation이 없습니다. 이는 PyTorch의 cross entropy loss가 자동으로 softmax activation을 연산해주기 때문입니다.</p>
<p>HINT: For convolutions: <a href="http://pytorch.org/docs/stable/nn.html#torch.nn.functional.conv2d">http://pytorch.org/docs/stable/nn.html#torch.nn.functional.conv2d</a>; pay attention to the shapes of convolutional filters!</p>
<pre><code class="language-python"># Req. 1-2    Three-Layer ConvNet 의 forward 패스 Tensor 연산으로 설계하기
def three_layer_convnet(x, params):
    &quot;&quot;&quot;
    아래 정의된 모델은 3개의 컨볼루션 레이어를 갖는 네트워크의 forward 패스를 수행합니다.

    Inputs:
    - x: 이미지의 minibatch로 구성된 (N, 3, H, W) shape의 PyTorch 텐서
    - params: 네트워크의 weights와 biases를 담은 PyTorch 텐서의 리스트, 아래 내용들 포함
      - conv_w1: PyTorch Tensor of shape (channel_1, 3, KH1, KW1) giving weights
        for the first convolutional layer
      - conv_b1: PyTorch Tensor of shape (channel_1,) giving biases for the first
        convolutional layer
      - conv_w2: PyTorch Tensor of shape (channel_2, channel_1, KH2, KW2) giving
        weights for the second convolutional layer
      - conv_b2: PyTorch Tensor of shape (channel_2,) giving biases for the second
        convolutional layer
      - fc_w: PyTorch Tensor giving weights for the fully-connected layer.
      - fc_b: PyTorch Tensor giving biases for the fully-connected layer.

    Returns:
    - scores: PyTorch Tensor of shape (N, C) giving classification scores for x
    &quot;&quot;&quot;
    conv_w1, conv_b1, conv_w2, conv_b2, fc_w, fc_b = params
    scores = None
    ################################################################################
    # TODO: Implement the forward pass for the three-layer ConvNet.                #
    ################################################################################
    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    F=torch.nn.functional.conv2d
    x1=torch.nn.functional.conv2d(x,conv_w1,padding=2)+conv_b1.view(1,-1,1,1)
    x2=torch.nn.functional.conv2d(x1.clamp(min=0),conv_w2,padding=1)+conv_b2.view(1,-1,1,1)
    x3=x2.view(x1.shape[0],-1).clamp(min=0).mm(fc_w)+fc_b
    scores=x3

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
    ################################################################################
    #                                 END OF YOUR CODE                             #
    ################################################################################
    return scores</code></pre>
<p>Forward 패스에 해당하는 ConvNet을 정의한 이후 다음 cell을 실행하여 구현한 코드를 확인해봅니다.</p>
<p>다음 함수를 실행하면, (64,10) shape을 갖는 score값을 출력하게 됩니다.</p>
<pre><code class="language-python">def three_layer_convnet_test():
    x = torch.zeros((64, 3, 32, 32), dtype=dtype)  # minibatch size 64, image size [3, 32, 32]

    conv_w1 = torch.zeros((6, 3, 5, 5), dtype=dtype, requires_grad=True)  # [out_channel, in_channel, kernel_H, kernel_W]
    conv_b1 = torch.zeros((6,), requires_grad=True)  # out_channel
    conv_w2 = torch.zeros((9, 6, 3, 3), dtype=dtype, requires_grad=True)  # [out_channel, in_channel, kernel_H, kernel_W]
    conv_b2 = torch.zeros((9,), requires_grad=True)  # out_channel

    # you must calculate the shape of the tensor after two conv layers, before the fully-connected layer
    fc_w = torch.zeros((9 * 32 * 32, 10), requires_grad=True)
    fc_b = torch.zeros(10, requires_grad=True)

    scores = three_layer_convnet(x, [conv_w1, conv_b1, conv_w2, conv_b2, fc_w, fc_b])
    print(scores.size())  # you should see [64, 10]
three_layer_convnet_test()</code></pre>
<h3 id="barebones-pytorch-initialization">Barebones PyTorch: Initialization</h3>
<p>몇가지 utility 메소드를 활용하여 모델의 weight matrices를 초기화해봅니다.</p>
<p>random_weight(shape) 은 weight값을 Kaiming normalization method로 초기화 합니다.</p>
<p>zero_weight(shape) 은 wieght값을 0으로 초기화 합니다.</p>
<p>random_weight 함수는 Kaiming normal initialization method로, 아래의 논문을 참고하면 됩니다:</p>
<p>He et al, Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification, ICCV 2015, <a href="https://arxiv.org/abs/1502.01852">https://arxiv.org/abs/1502.01852</a></p>
<pre><code class="language-python">def random_weight(shape):
    &quot;&quot;&quot;
    Weight을 위한 랜덤 텐서를 생성합니다. 이때 requires_grad=True로 세팅해주어야 
    추후에 backward 패스에서 사용할 gradient를 자동으로 계산할 수 있습니다.
    여기서 Kaiming normalization을 사용합니다: sqrt(2 / fan_in)
    &quot;&quot;&quot;
    if len(shape) == 2:  # FC weight
        fan_in = shape[0]
    else:
        fan_in = np.prod(shape[1:]) # conv weight [out_channel, in_channel, kH, kW]
    # randn is standard normal distribution generator. 
    w = torch.randn(shape, device=device, dtype=dtype) * np.sqrt(2. / fan_in)
    w.requires_grad = True
    return w

def zero_weight(shape):
    return torch.zeros(shape, device=device, dtype=dtype, requires_grad=True)

# create a weight of shape [3 x 5]
# you should see the type `torch.cuda.FloatTensor` if you use GPU. 
# Otherwise it should be `torch.FloatTensor`
random_weight((3, 5))</code></pre>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/fd132cb1-6b53-44e8-9f77-b53678ab9212/image.png" alt=""></p>
<h3 id="barebones-pytorch-check-accuracy">Barebones PyTorch: Check Accuracy</h3>
<p>모델을 학습할 때 다음의 함수를 활용하여 모델의 정확성을 확인합니다. 정확도를 확인할 때에는 gradient를 계산할 필요가 없습니다. 따라서 torch.no_grad()를 입력하여 계산 그래프의 gradient 계산을 막습니다.</p>
<pre><code class="language-python">def check_accuracy_part2(loader, model_fn, params):
    &quot;&quot;&quot;
    분류 모델의 정확성 측정

    Inputs:
    - loader: A DataLoader for the data split we want to check
    - model_fn: A function that performs the forward pass of the model,
      with the signature scores = model_fn(x, params)
    - params: List of PyTorch Tensors giving parameters of the model

    Returns: Nothing, but prints the accuracy of the model
    &quot;&quot;&quot;
    split = &#39;val&#39; if loader.dataset.train else &#39;test&#39;
    print(&#39;Checking accuracy on the %s set&#39; % split)
    num_correct, num_samples = 0, 0
    with torch.no_grad(): # gradient 계산할 필요가 없어, computational graph 를 그리지 않게 하기위해 with torch.no_grad() 사용
        for x, y in loader:
            x = x.to(device=device, dtype=dtype)  # move to device, e.g. GPU
            y = y.to(device=device, dtype=torch.int64)
            scores = model_fn(x, params)
            _, preds = scores.max(1)
            num_correct += (preds == y).sum()
            num_samples += preds.size(0)
        acc = float(num_correct) / num_samples
        print(&#39;Got %d / %d correct (%.2f%%)&#39; % (num_correct, num_samples, 100 * acc))</code></pre>
<h3 id="barebones-pytorch-training-loop">BareBones PyTorch: Training Loop</h3>
<p>이제 학습 loop를 작성하여 네트워크를 학습합니다. 학습은 stochastic gradient descent를 사용합니다. 또한 torch.functional.cross_entropy 를 사용하여 loss를 측정합니다 read about it here.</p>
<p>학습 loop는 네트워크 함수와 초기화된 weight 파라미터 ([w1, w2] in our example), 그리고 learning rate을 입력으로 받습니다.</p>
<pre><code class="language-python">def train_part2(model_fn, params, learning_rate):
    &quot;&quot;&quot;
    CIFAR-10에 대하여 모델 학습하기.

    Inputs:
    - model_fn: 모델의 forward 패스를 수행하는 PyTorch 함수.
      이는 이미지 데이터 x와 모델 weight의 list를 입력으로 받아 score를 출력하는 함수이다.
      scores = model_fn(x, params)
    - params: 모델 weight의 list
    - learning_rate: scalar 값

    Returns: Nothing
    &quot;&quot;&quot;
    for t, (x, y) in enumerate(loader_train):
        # 데이터를 적절한 device에 올리기
        x = x.to(device=device, dtype=dtype)
        y = y.to(device=device, dtype=torch.long)

        # Forward 패스를 수행하고, loss 계산하기
        scores = model_fn(x, params)
        loss = F.cross_entropy(scores, y)

        # Backward 패스 수행
        loss.backward()

        # 모델의 weight 업데이트하기. wieght 업데이트 시에는 gradient 계산은 
        # torch.no_grad()를 사용하여 막는다
        with torch.no_grad():
            for w in params:
                w -= learning_rate * w.grad

                # Backward 패스를 마친 이후 수동으로 gradient 값을 0으로 초기화
                w.grad.zero_()

        if t % print_every == 0:
            print(&#39;Iteration %d, loss = %.4f&#39; % (t, loss.item()))
            check_accuracy_part2(loader_val, model_fn, params)
            print()</code></pre>
<h3 id="barebones-pytorch-train-a-two-layer-network">BareBones PyTorch: Train a Two-Layer Network</h3>
<p>이제 학습 loop 실행을 시작합니다. 먼저 앞서 정의한 weight 초기화 함수를 활용하여 w1와 w2를 정의합니다.</p>
<p>CIFAR-10의 각 미니배치의 Tensor shape은 [64, 3, 32, 32] 입니다.</p>
<p>이미지 데이터 x를 flatten한 뒤에 shape은 [64, 3 * 32 * 32]가 되어야 합니다. 이는 w1의 첫 dimension의 사이즈와 동일합니다. w1의 두번째 dimension의 사이즈는 hidden 레이어의 사이즈와 동일하고, 이는 동시에 w2의 첫 dimension의 사이즈와 동일합니다.</p>
<p>마지막으로, 네트워크의 출력은 10-dimensional vector이고, 이는 10개 클래스에 대한 확률을 나타냅니다.</p>
<p>별도로 hyperparameters를 수정하지 않고도 한 에폭 이후 40% 이상의 분류 정확도를 보이면 성공입니다.</p>
<pre><code class="language-python">hidden_layer_size = 4000
learning_rate = 1e-2

w1 = random_weight((3 * 32 * 32, hidden_layer_size))
w2 = random_weight((hidden_layer_size, 10))


train_part2(two_layer_fc, [w1, w2], learning_rate)</code></pre>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/bccaf530-d50f-405d-9418-822a4be806f6/image.png" alt=""></p>
<h3 id="barebones-pytorch-training-a-convnet">BareBones PyTorch: Training a ConvNet</h3>
<p>Two-layer 네트워크 학습이 마쳤다면, 여기에서는 ConvNet을 학습시켜 봅니다. 여기서 정의해야할 네트워크는 다음과 같은 구조를 가져야 합니다.</p>
<p>Convolutional layer (with bias) with 32 5x5 filters, with zero-padding of 2
ReLU
Convolutional layer (with bias) with 16 3x3 filters, with zero-padding of 1
ReLU
Fully-connected layer (with bias) to compute scores for 10 classes
모든 weight matrices는 앞서 정의한 random_weight 함수를 사용하여 초기화 시켜 주어야 하고, bias vector는 zero_weight 함수로 초기화 시켜 줍니다.</p>
<p>별도로 hyperparameters를 수정하지 않고도 한 에폭 이후 42% 이상의 분류 정확도를 보이면 성공입니다.</p>
<pre><code class="language-python"># Req. 1-3    Three-Layer ConvNet의 weight 파라미터를 Tensor 형태로 초기화

learning_rate = 3e-3

channel_1 = 32
channel_2 = 16

conv_w1 = None
conv_b1 = None
conv_w2 = None
conv_b2 = None
fc_w = None
fc_b = None

################################################################################
# TODO: Initialize the parameters of a three-layer ConvNet.                    #
################################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

conv_w1=random_weight([32,3,5,5])
conv_b1=zero_weight(32)
conv_w2=random_weight([16,32,3,3])
conv_b2=zero_weight(16)
fc_w=random_weight([16*32*32,10])
fc_b=zero_weight(10)

# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
################################################################################
#                                 END OF YOUR CODE                             #
################################################################################

params = [conv_w1, conv_b1, conv_w2, conv_b2, fc_w, fc_b]
train_part2(three_layer_convnet, params, learning_rate)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch] 이미지 분류기 구현 - 데이터셋 준비 및 전처리]]></title>
            <link>https://velog.io/@hang_geee/Artificial-Intelligence-Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%85%8B-%EC%A4%80%EB%B9%84-%EB%B0%8F-%EC%A0%84%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@hang_geee/Artificial-Intelligence-Pytorch-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B6%84%EB%A5%98%EA%B8%B0-%EA%B5%AC%ED%98%84-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%85%8B-%EC%A4%80%EB%B9%84-%EB%B0%8F-%EC%A0%84%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 04 Sep 2022 05:14:32 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터셋-준비-및-전처리">데이터셋 준비 및 전처리</h1>
<ul>
<li><p>작성된 데이터로더 부분에서 CIFAR-10 train, validation, test set을 다운 받고, 이미지 데이터를 정규화 한 뒤, 데이터로더에 넣어 학습을 위한 준비하는 과정을 살펴보고 이해합니다.</p>
</li>
<li><p>이때 torch.utils.data.DataLoader의 argument들에 대해서 링크를 참고하여 실습합니다.</p>
</li>
</ul>
<hr>
<h2 id="데이터셋-준비">데이터셋 준비</h2>
<h3 id="cifar-10-">CIFAR-10 ?</h3>
<ul>
<li><p>CIFAR-10은 3x32x32 크기의 이미지로 총 10개의 클래스(‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’) 로 구성된 60000장의 데이터셋</p>
</li>
<li><p>torchvision을 사용하여 CIFAR-10 을 load 할 수 있습니다.</p>
</li>
<li><p>torchvision.transform 을 사용하여 데이터를 normalize할 수 있습니다.</p>
</li>
</ul>
<h4 id="references">references</h4>
<p><a href="https://pytorch.org/docs/stable/data.html">dataloader(pytorch doc)</a></p>
<p><a href="https://subinium.github.io/pytorch-dataloader/">dataloader parameter(blog)</a></p>
<p>추가적으로 컴퓨터 비전 데이터를 다룰 때 <code>torchvision</code>이라는 패키지를 사용하면 유용하고, 여러 데이터셋들을 다운 받을 수 있습니다.</p>
<pre><code class="language-python"># Req. 1-1    데이터셋 준비 및 전처리, 시각화
NUM_TRAIN = 49000

# torchvision.transforms 내에는 데이터 전처리 및 data augmentation을 위한 패키지를 제공
# 본 실습에서 [0,1] 범위의 데이터셋을 [-1, 1] 범위의 값으로 normalize하도록 transform 정의
transform = T.Compose([
                T.ToTensor(),
                T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
            ])

# Dataset을 (train / val / test)으로 분리
# 분리된 Datasets를 DataLoader로 wrap하여, 추후 각 data들이 매 iteration마다 미니배치로 제공됨
cifar10_train = dset.CIFAR10(&#39;./cores/datasets/&#39;, train=True, download=True,
                             transform=transform)
loader_train = DataLoader(cifar10_train, batch_size=64, 
                          sampler=sampler.SubsetRandomSampler(range(NUM_TRAIN)))

cifar10_val = dset.CIFAR10(&#39;./cores/datasets/&#39;, train=True, download=True,
                           transform=transform)
loader_val = DataLoader(cifar10_val, batch_size=64, 
                        sampler=sampler.SubsetRandomSampler(range(NUM_TRAIN, 50000)))

cifar10_test = dset.CIFAR10(&#39;./cores/datasets/&#39;, train=False, download=True, 
                            transform=transform)
loader_test = DataLoader(cifar10_test, batch_size=64)

# CIFAR10의 10개의 class 정의
classes = (&#39;plane&#39;, &#39;car&#39;, &#39;bird&#39;, &#39;cat&#39;,&#39;deer&#39;, &#39;dog&#39;, &#39;frog&#39;, &#39;horse&#39;, &#39;ship&#39;, &#39;truck&#39;)</code></pre>
<h3 id="torchvisiontransformnormalize">torchvision.transform.normalize</h3>
<p>normalize는 T.Normalize((mean1, -, -), (std1, -, -)) 식으로 쓰는데
첫 번째 괄호는 mean 두 번째 괄호는 std다.
X - mean / std 형태로 정규화하므로
기존의 범위인 [0, 1]에 적용하면
(0-0.5)/0.5 = -1
(1-0.5)/0.5 = 1이 되어
[-1, 1] 범위의 값으로 normalize하도록 transform을 정의한 것이다.</p>
<h2 id="데이터-시각화">데이터 시각화</h2>
<ul>
<li>matplotlib는 python visualization library</li>
<li>matplotlib의 imshow 함수를 데이터들을 시각화 할 수 있습니다.</li>
</ul>
<h4 id="references-1">references</h4>
<p><a href="https://matplotlib.org/api/_as_gen/matplotlib.pyplot.imshow.html">matplotlib doc</a></p>
<pre><code class="language-python"># 이미지를 시각화하는 함수
def visualize(img):
    ################################################################################
    # TODO: 시각화를 위한 코드 작성.                                                    #
    ################################################################################
    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
    pass
    # 1) [-1, 1] 범위로 normalize된 데이터를 [0,1] 범위로 unnormalize 
    # 2) img를 numpy값으로 변환
    # 3) plt.imshow함수로 시각화
    img = (img + 1) / 2
    # img = img / 2 + 0.5
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()
    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
    ################################################################################
    #                                 END OF YOUR CODE                             #
    ################################################################################


# 트레이닝 데이터를 랜덤 샘플
dataiter = iter(loader_train)
images, labels = dataiter.next() ## image

# show images
visualize(torchvision.utils.make_grid(images))</code></pre>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/8fea7170-40b4-4bb3-87e4-b26bd43d1cf1/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Artificial Intelligence] 기계학습, 최적화
]]></title>
            <link>https://velog.io/@hang_geee/Artificial-Intelligence-%EA%B8%B0%EA%B3%84%ED%95%99%EC%8A%B5-%EC%B5%9C%EC%A0%81%ED%99%94</link>
            <guid>https://velog.io/@hang_geee/Artificial-Intelligence-%EA%B8%B0%EA%B3%84%ED%95%99%EC%8A%B5-%EC%B5%9C%EC%A0%81%ED%99%94</guid>
            <pubDate>Fri, 26 Aug 2022 08:20:38 GMT</pubDate>
            <description><![CDATA[<h2 id="기계학습이란-무엇인가">기계학습이란 무엇인가?</h2>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/1bb1e4bc-d344-47e6-b8ab-8ecc357ec4e4/image.png" alt=""></p>
<ul>
<li>최적화<ul>
<li>데이터를 줬을 때 그 관계를 찾는 것</li>
</ul>
</li>
<li>일반화<ul>
<li>본 적이 없는 새로운 데이터가 들어와도 적절한  출력을 내보내서 정답을 맞췄으면 일반화가 잘 되었다고 표현함</li>
</ul>
</li>
</ul>
<p>최적화를 통해 f를 잘 찾고 새로운 데이터가 들어와도 아웃풋 잘 나왔을 때(일반화) 기계학습이라고 함</p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/b1437ede-ccb5-45f2-b0ba-e4887100745b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/500e9b6c-b68d-402c-a55f-1d440771b350/image.png" alt=""></p>
<h3 id="평가할-수-있는-기준-→-loss-function-cost">평가할 수 있는 기준 → loss function, cost</h3>
<ul>
<li>목표값과 예측값과의 오차를 제곱하고 평균 계산</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/7e011529-8698-439f-bb04-9159791ae2e1/image.png" alt=""></p>
<h3 id="x-값을-넣어봄으로써-데이터가-얼마나-잘-맞는지-확인">x 값을 넣어봄으로써 데이터가 얼마나 잘 맞는지 확인</h3>
<p>각각의 데이터가 얼마나 맞는지 물어본다.</p>
<p>어마어마하게 큰 오차(error) 발생</p>
<h2 id="어떻게-현재-모델을-개선할-수-있을까">어떻게 현재 모델을 개선할 수 있을까?</h2>
<p>W,b를 랜덤으로 바꿔볼 수도 있지만 범위가 너무 크기 때문에 못 찾을 수도 있다.</p>
<p>효율적으로 하려면?</p>
<p>현재의 위치에서 loss를 파악 → 조금 움직였을 때 loss의 변화 파악</p>
<p>가장 급격하게 내려갈 수 있는 부분을 찾아서 W,b를 일정 간격 변화 시켜본다.</p>
<p>또 다른 그래프를 통해 loss를 측정해보고 더 바뀌면 어떻게 될까… 지속적인 탐색</p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/643ac1df-6187-4f14-bc0c-d55d1795acbd/image.png" alt=""></p>
<h2 id="gradient-direction">gradient direction</h2>
<ul>
<li>어떤 방향으로 이동했을 때 Loss가 떨어지느냐</li>
<li>많이 이동하면 좋다? → X, 꼭 그렇지 않다. 꼭 계속 감소하는 것은 아니니까</li>
<li>learning rate(알파)로 step size를 결정</li>
<li>gradient → 어떤 방향?</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/4471ac3d-fafb-42d9-8ef1-6c6d319fe878/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/1f107699-69a5-4bae-92ae-93187e9f8d27/image.png" alt=""></p>
<h2 id="epoch--train-dataset-전체를-한번-다-이용하면-1씩-상승">epoch : train dataset 전체를 한번 다 이용하면 1씩 상승</h2>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/55c3864c-4d43-481a-9e66-0f5baeca99aa/image.png" alt=""></p>
<h3 id="underfitting-vs-overfitting">underfitting vs overfitting</h3>
<ul>
<li>그나마 overfitting이 낫다.</li>
<li>underfitting은 학습 데이터 자체도 fitting이 잘 안 됨<ul>
<li>모델 설정부터 잘못 되었다.</li>
</ul>
</li>
<li>둘 다 model의 mismatch</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/ecb79f03-bb00-4ed5-954f-8205985da95f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/56dc1a78-6a88-47af-921a-e989a6f801e9/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/e856c398-d0cb-41f7-8e81-c435e7d39f43/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/962b23db-bece-457b-a143-ed9cf0c2ab6c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/9de0bf52-c708-4afa-bf07-81182975f361/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Pytorch] practice]]></title>
            <link>https://velog.io/@hang_geee/Pytorch-practice</link>
            <guid>https://velog.io/@hang_geee/Pytorch-practice</guid>
            <pubDate>Wed, 24 Aug 2022 16:34:17 GMT</pubDate>
            <description><![CDATA[<h1 id="day1-실습">Day1 실습</h1>
<p><em>Pytorch를 다루는데 꼭 필요한 tensor에 대한 개념과 선형 모델로 간단한 데이터 모델을 예측하는 모델을 만들어보자</em></p>
<h3 id="tensor-manipulation">Tensor manipulation</h3>
<ul>
<li>python의 numpy 패키지와 pytorch는 vector, matrix, tensor를 쉽게 다룰 수 있는 많은 함수와 자료구조를 제공합니다. 따라서 공학과 인공지능을 공부하기 위해서 필수적으로 알아두어야 하는 라이브러리들입니다. 간단한 선형 인공지능 모델을 다루기 전에 많이 쓰이고 유용한 함수들을 먼저 공부해봅시다.</li>
</ul>
<p><a href="https://wikidocs.net/52460">텐서 조작하기 레퍼런스</a></p>
<ol>
<li><strong>텐서의 차원과 형태 관련</strong></li>
</ol>
<blockquote>
<pre><code>X, Y        # Tensors
X.dim()  # 차원을 출력
X.shape, X.size() # 텐서의 모양을 출력</code></pre></blockquote>
<pre><code class="language-python">import torch
X =torch.rand(3,4, 5)

print(&#39;X.dim()&#39;, X.dim())
print(&#39;X.shape&#39;, X.shape)
print(&#39;X.size()&#39;, X.size())
X.dim() 3
X.shape torch.Size([3, 4, 5])
X.size() torch.Size([3, 4, 5])</code></pre>
<h3 id="그렇다면-shpae과-size의-차이는">그렇다면 shpae과 size()의 차이는??</h3>
<ul>
<li>shape은 변수이고 size()는 메서드이다.</li>
</ul>
<ol>
<li><strong>Mul 과 Matmul의 차이</strong></li>
</ol>
<blockquote>
<pre><code>X.matmul(Y) # 행렬 곱 (내적)
X.mul(Y)    # X*Y 와 동일. 각 원소 별로 곱하는 연산.</code></pre></blockquote>
<pre><code class="language-python">X = torch.rand(3,2,5)
Y = torch.rand(3,5,3)

D = X.matmul(Y) # 행렬 곱 (내적)
print(D)
print(D.shape)
# X.mul(Y)    # X*Y 와 동일. 각 원소 별로 곱하는 연산.
tensor([[[1.7955, 1.2414, 1.4892],
         [1.4453, 1.0660, 1.0680]],

        [[1.5991, 1.2970, 1.6333],
         [1.0118, 1.4612, 0.9563]],

        [[0.4231, 0.7838, 1.0513],
         [0.8023, 1.0286, 1.2409]]])
torch.Size([3, 2, 3])</code></pre>
<ol>
<li><strong>Broadcasting</strong></li>
</ol>
<blockquote>
<p>X의 shape이 [100,1,20] 이고, Y가 [100,40,20] 일때, 크기가 다르기 때문에 원소별 연산 (예; +, * 등) 적용이 불가한 것처럼 보이지만, numpy와 pytorch는 broadcasting을 지원하여, X의 두번째 차원 1인 경우, Y의 두번째 차원인 40에 맞춰 X의 값들을 반복 복제하는 식으로 자동으로 크기를 조절하여 연산이 가능하도록 만들어줍니다. 매번 복제하는 코드를 명시적으로 구현할 필요 없이, 매우 편리하게 응용될 수 있지만, 의도치 않게 broadcasting이 되면 디버깅을 할때 오류를 잡는 것이 어려워 질 수 있으므로 꼭 주의하여 사용 것이 좋습니다.</p>
</blockquote>
<ol>
<li><strong>view() (numpy의 경우는 reshape())</strong></li>
</ol>
<blockquote>
<p>텐서의 shape를 바꿔야할 경우 사용합니다. 매우 자주 쓰이는 함수이므로 꼭 알아두세요!</p>
</blockquote>
<pre><code class="language-python">X.shape
X.view(3,10).shape
torch.Size([3, 10])</code></pre>
<ol>
<li><strong>axis개념</strong></li>
</ol>
<blockquote>
<p>많은 함수에서 매개변수로 요구되는 개념입니다. 다차원 텐서에 해당 함수 연산을 어떤 축으로 적용 할지를 결정하는데 사용합니다.\ 예; np.concaternate((A1,B1),axis = 0) 이런식으로 함수의 매개변수 중 하나로 자주 등장합니다. \ \ 참고자료&gt; <a href="http://taewan.kim/post/numpy_sum_axis/">http://taewan.kim/post/numpy_sum_axis/</a> \</p>
</blockquote>
<ol>
<li><strong>squeeze &amp; unsqueeze</strong></li>
</ol>
<blockquote>
<p>특정 차원이 1인 경우 축소시키거나 차원을 확장시킬 때 사용합니다. 자주 등장하므로 알아두면 좋습니다.</p>
<pre><code>torch.squeeze(X) # X: [100,1,20] =&gt; [100,20]</code></pre></blockquote>
<ol>
<li><strong>type casting</strong></li>
</ol>
<blockquote>
<p>컴퓨터는 여러가지 자료형(int,float,uint8 등)이 있지만 type이 같지 않으면 수치적인 문제가 발생할 수 있기 때문에 항상 유의하는 것이 좋습니다. 따라서 자료형이 무엇인지 그리고 어떻게 바꾸는지 알고 있어야 합니다.</p>
</blockquote>
<ol>
<li><strong>concatenate</strong></li>
</ol>
<blockquote>
<p>두 개 이상의 텐서들을 지정된 축으로 쌓아서 더 큰 텐서를 만드는 함수. 하나의 텐서로 합치기 위한 입력 텐서들은 concatenate하는 축을 제외하고는 모두 같은 크기를 가져야 합니다.</p>
</blockquote>
<hr>
<h2 id="1일차-실습">1일차 실습</h2>
<p>선형 모델 f(x)=Wx+b에 대해서, 주어진 데이터를 제일 잘 표현하는 learnable parameter인 Weight W와 Bias b를 찾는 방법의 예제 입니다. 이 실습에서는 parameter 탐색을 하는 다양한 방법 중 가장 Naive한 방법으로 찾는 예제를 보여줍니다.</p>
<p>먼저 필요한 라이브러리들을 import합니다.</p>
<h3 id="w와-b를-찾는다최적화한다">W와 b를 찾는다(최적화한다.)</h3>
<pre><code class="language-python">from __future__ import print_function, division
import os
import torch
import pandas as pd
from skimage import io, transform
import numpy as np
import warnings
warnings.filterwarnings(&quot;ignore&quot;)</code></pre>
<p>다음의 그래프는 지난 시험의 결과를 토대로 서로 다른 학생의 공부시간과 성적의 관계를 모아놓은 표입니다.</p>
<h2 id="q1-study-time과-grade-각각을-torchfloattensor로-작성하시고-shape는-7-1-dimension은-2로-만들어-보세요"><strong>Q1) study time과 Grade 각각을 torch.FloatTensor로 작성하시고, shape는 [7, 1], dimension은 2로 만들어 보세요.</strong></h2>
<h2 id="q2-위에서-만든-x_train과-y_train이-잘-만들어졌는지-시각화-해보세요"><strong>Q2) 위에서 만든 x_train과 y_train이 잘 만들어졌는지 시각화 해보세요.</strong></h2>
<p><a href="https://kongdols-room.tistory.com/91">시각화 참고 링크</a></p>
<p>![스크린샷 2022-08-24 오후 5.00.16](무제.assets/스크린샷 2022-08-24 오후 5.00.16.png)</p>
<p>이번에는 GDrive와 Colab의 csv 파일을 읽어오는 법과 외부 인터넷 페이지 상의 csv 파일을 읽어오는 법에 배워보도록 하겠습니다.</p>
<p>하단의 링크에는 health_data.csv 파일이 들어있습니다. 이 파일을 다운받은 후 google drive의 가장 기본 디렉토리인 &quot;내 드라이브&quot;로 옮겨주세요.</p>
<p><a href="https://drive.google.com/file/d/1C1_Sh2Rw5St58NLvDer62cJd-bvUvUcs/view?usp=sharing">https://drive.google.com/file/d/1C1_Sh2Rw5St58NLvDer62cJd-bvUvUcs/view?usp=sharing</a></p>
<p>Colab과 Gdrive 모두 google에서 제공하는 서비스이므로 2개를 연동시킬 수 있습니다.</p>
<p>하단의 링크를 참조하시면 친절한 설명이 되어있습니다.</p>
<p><a href="https://starrykss.tistory.com/1029">https://starrykss.tistory.com/1029</a></p>
<pre><code class="language-python">from google.colab import drive
drive.mount(&#39;/content/gdrive&#39;)  Mounted at /content/gdrive

Mounted at /content/gdrive</code></pre>
<p>gdrive와 colab을 연동시켰다면 gdrive에서 csv 파일을 가져와 사용해봅시다.</p>
<pre><code class="language-python">import pathlib
path = pathlib.Path(&#39;/content/gdrive/My Drive/health_data.csv&#39;) 

data_file = pd.read_csv(path)
data_file.head()</code></pre>
<p>![스크린샷 2022-08-24 오후 5.13.35](무제.assets/스크린샷 2022-08-24 오후 5.13.35.png)</p>
<p>이 데이터는 정제가 되지 않아 데이터가 불완전 한 상태입니다. NaN은 숫자로 표현 불가한 값으로 최적의 Weight W와 Bias b 를 찾는데 방해가 됩니다. 이런 데이터들을 모두 제거하는 전처리 작업을 해봅시다.</p>
<h2 id="q3-우선-데이터셋-안에-nan-혹은-null이-있는지-체크합니다">Q3) 우선 데이터셋 안에 NaN 혹은 null이 있는지 체크합니다.</h2>
<pre><code class="language-python">pd.isnull(data_file)</code></pre>
<ul>
<li>Isnull 함수를 활용하여 결측값을 체크 했는데 모든 셀에 대해서 False True 형태로 출력 됨</li>
</ul>
<p>![스크린샷 2022-08-24 오후 5.20.28](무제.assets/스크린샷 2022-08-24 오후 5.20.28.png)</p>
<h4 id="정답">정답</h4>
<pre><code class="language-python">data_file.isnull()</code></pre>
<h2 id="q4미완성-되어-있는-행을-제거해보세요"><strong>Q4)미완성 되어 있는 행을 제거해보세요.</strong></h2>
<p>(힌트1) pandas의 dropna()이용</p>
<p>(힌트2) axis에 대한 개념을 모르겠다면 tensor manipulation 부분으로 가서 다시 공부해보세요!</p>
<pre><code class="language-python">data_file = pd.read_csv(path).dropna(axis=0)
data_file.head()</code></pre>
<ul>
<li>pandas의 dropna()를 이용했고 axis=0을 주어 결측값이 있는 행을 없앴다.</li>
<li>결측값이 있는 열을 없애고 싶다면 axis=1을 주면 된다.</li>
</ul>
<p>![스크린샷 2022-08-24 오후 5.26.15](무제.assets/스크린샷 2022-08-24 오후 5.26.15.png)</p>
<h4 id="정답-1">정답</h4>
<pre><code class="language-Python">data_file = data_file.dropna(index=0).reset_index(drop=True)
data_file.head()</code></pre>
<h2 id="q5-csv-파일은-아직-pytorch에서-사용할-수-있는-텐서의-형태가-아니므로-tensor의-형태로-바꿔보세요"><strong>Q5) csv 파일은 아직 pytorch에서 사용할 수 있는 텐서의 형태가 아니므로 tensor의 형태로 바꿔보세요</strong></h2>
<pre><code class="language-Python">height = 
weight = </code></pre>
<p>![스크린샷 2022-08-24 오후 6.23.34](무제.assets/스크린샷 2022-08-24 오후 6.23.34.png)</p>
<p>이런식으로 하면 되지 않을까 생각했는데 실패 ㅠㅠ</p>
<h3 id="정답-2">정답</h3>
<pre><code class="language-python">height = torch.tensor(data_file.height)
weight = torch.tensor(data_file.weight)</code></pre>
<h2 id="q6-공부시간과-성적-그래프를-입력할-때-처럼-shape와-dimension을-맞춰주시고-자료형은-float-타입으로-변환시켜보세요"><strong>Q6) 공부시간과 성적 그래프를 입력할 때 처럼 shape와 dimension을 맞춰주시고, 자료형은 float 타입으로 변환시켜보세요</strong></h2>
<p>(힌트) .view() 함수이용, shape = (50, 1), dimension = 2</p>
<pre><code class="language-python">x_train = height.view([height. shape[0] ,1]).float()
y_train = weight.view([weight. shape[0] ,1]).float()</code></pre>
<h2 id="q7-랜덤으로-만든-데이터를-기존-데이터에-추가해봅시다-x_train-dataset의-경우-145부터-190사이의-랜덤한-숫자-50개-y_train-dataset의-경우-45부터-85-사이의-랜덤한-숫자-50개를-생성하여-concatenate를-시킵니다"><strong>Q7) 랜덤으로 만든 데이터를 기존 데이터에 추가해봅시다. x_train dataset의 경우 145부터 190사이의 랜덤한 숫자 50개, y_train dataset의 경우 45부터 85 사이의 랜덤한 숫자 50개를 생성하여 concatenate를 시킵니다.</strong></h2>
<p>(힌트) 랜덤 생성 함수 torch.rand()함수 사용, concatenate의 경우 torch.cat()함수를 사용합니다. axis도 데이터의 형태에 맞게 사용하시면 됩니다.</p>
<pre><code class="language-python">x_train = torch.cat((torch.rand(50.1)*45+145,x_train). axis = 0)
y_train = torch.cat((torch.rand(50.1)*45+145,y_train). axis = 0)</code></pre>
<p>![스크린샷 2022-08-25 오전 1.29.36](무제.assets/스크린샷 2022-08-25 오전 1.29.36.png)</p>
<ul>
<li>why not</li>
</ul>
<h2 id="q8-training-data가-잘-등록이-되었는지-matplotlib-함수를-통해-시각화-해보세요"><strong>Q8) training data가 잘 등록이 되었는지 matplotlib 함수를 통해 시각화 해보세요.</strong></h2>
<pre><code class="language-python">%matplotlib inline
import matplotlib.pyplot as plt

x = x_train
y = y_train

plt.scatter(x,y)
plt.show()</code></pre>
<h2 id="q9-이번에는-아래의-파란선처럼-data에-잘-표현하는-직선y--wx--b을-찾으려합니다-x와-y는-데이터셋으로부터-주어진-데이터들이기-때문에-w와-b를-결정하면-됩니다-기계가-학습하는-방법과-관련된-것을-수업에서-다루지-않았기-때문에-가장-간단한-방법인-랜덤하게-w와-b를-바꿔가면서-training-dataset을-가장-잘-fitting하는-파라메터들을-찾아봅시다"><strong>Q9) 이번에는 아래의 파란선처럼 data에 잘 표현하는 직선($y = Wx + b$)을 찾으려합니다. x와 y는 데이터셋으로부터 주어진 데이터들이기 때문에 W와 b를 결정하면 됩니다. 기계가 학습하는 방법과 관련된 것을 수업에서 다루지 않았기 때문에, 가장 간단한 방법인 랜덤하게 W와 b를 바꿔가면서 training dataset을 가장 잘 fitting하는 파라메터들을 찾아봅시다.</strong></h2>
<h2 id="q10-총-50000번-w-b-값을-바꾸어-training-dataset에-가장-잘-fitting-하는-w-b-값을-찾아봅시다-w-b가-가질-수-있는-모든-값을-다-시도해보는-것은-무한한-가능성이-있어서-어마어마하게-많은-시간을-이용해야-합니다-이번-실습과-같이-작은-문제에서는-적용할-수-있을지-모르겠지만-조금만-차원이-늘어나도-실용적이지-않게-됩니다-따라서-이번에는-복잡한-방법이-아니라-try--error를-통한-가장-간단한-방법을-시도해-봅시다-랜덤으로-실수를-생성하여-w-b에-할당-합니다-그렇게-정해진-w-b를-이용하여-y의-예측을-시도할-수-있습니다"><strong>Q10) 총 50000번 W, b 값을 바꾸어 training dataset에 가장 잘 fitting 하는 W, b 값을 찾아봅시다. W, b가 가질 수 있는 모든 값을 다 시도해보는 것은 무한한 가능성이 있어서 어마어마하게 많은 시간을 이용해야 합니다. 이번 실습과 같이 작은 문제에서는 적용할 수 있을지 모르겠지만 조금만 차원이 늘어나도 실용적이지 않게 됩니다. 따라서, 이번에는 복잡한 방법이 아니라 Try &amp; Error를 통한 가장 간단한 방법을 시도해 봅시다. 랜덤으로 *실수*를 생성하여 W, b에 할당 합니다. 그렇게 정해진 W, b를 이용하여 y의 예측을 시도할 수 있습니다.</strong></h2>
<p>hypothesis=Wx+b</p>
<p>현재 구한 직선 (Hypothesis)이 데이터에 잘 fitting 되었는지 확인하는 방법으로는  Error ∣hypothesis−y∣의 합으로 구하며 이를 loss라고 명명합니다. 일반적으로는 L2 loss라 하여 간단히 (hypothesis−y)2를 사용하나, 본 예제에서는 데이터에 거짓 데이터(Outlier)들이 많이 포함되어 있어, 거짓 데이터에 강인하다고 알려진, L1 loss ∣hypothesis−y∣를 사용합니다. 이전에 구했던 loss의 값보다 더 작은 loss가 나올 경우 min_loss에 현재의 loss를, min_W과 min_b에는 현재 W와 b를 저장합니다.</p>
<p>50000번을 반복하여 생성된 직선을 matplotlib으로 시각화하여 얼마나 현재 training dataset에 얼마나 잘 fitting 되었는지 확인하여보세요.</p>
<p>(힌트) 랜덤으로 숫자를 생성하는 함수로는 torch.rand() 함수를 사용하고, 적당히 크기와 오프셋을 조정해주세요. ([출력범위] = 크기*[입력범위] + 오프셋)</p>
<p>(힌트) 파이썬의 기초가 약하여 if문, for문 같은 문법을 간단하게 공부하고 싶으시다면  wikidoc(<a href="https://wikidocs.net/book/1">https://wikidocs.net/book/1</a> : jump to python)을 참고하시면 도움이 될것입니다.</p>
<p>(+$\alpha$) |hypothesis - y|의 값들을 모두 더하는 가장 쉬운 방법은 for문을 사용하는 것이지만, 가장 짧게 작성할 수 있는 방법은 벡터화하여 연산하는 방법입니다. <a href="https://ooyoung.tistory.com/141">https://ooyoung.tistory.com/141</a> 벡터화와 관련된 간단한 설명이 되어있는 링크이며 벡터화를 시키지 않아도 문제를 푸는데는 지장이 없습니다.</p>
<pre><code class="language-python">#답안 작성

#문제를 푸는데 필요한 변수들이며 필요할 경우 추가 혹은 삭제하셔도 무방합니다.
iter = 50000 #loss값을 구하는 횟수로 총 50000번 
weight_max = 100 #&#39;[입력범위]&#39;로 random값의 weight 범위 제한 목적 ( -50 &lt; weight &lt; 50 )
bias_max = 150 #오프셋으로 random값의 bias 범위 제한 목적 (-150 &lt; bias &lt; 0)
min_loss = 1000000 #업데이트 된 가장 작은 값의 loss 저장 
min_W = 0 
min_b = 0

#dataset
x = x_train
y = y_train

def loss_fn(hypo, GT):
  return sum(abs(hypo - GT))

# [Do it yourself] 위의 변수들을 활용하여 문제를 풀어주세요.
for i in range(iter):
  W = 
  b = 
  hypothesis = 

  cur_loss = loss_fn(hypothesis,y)

  ... 

  if cur_loss &lt; min_loss:
    ...</code></pre>
<p>최종적으로 data에 직선을 잘 fitting 시켰는지 시각화 해봅시다</p>
<pre><code class="language-python"># 직선 시각화
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

x = x_train
y = y_train

plt.scatter(x, y)

t = np.arange(140.,190.,0.001)

plt.plot(t, min_W*t+min_b)
plt.xlabel(&#39;height (cm)&#39;)
plt.ylabel(&#39;weight (kg)&#39;)
plt.show()</code></pre>
<p>대략 아래와 같은 결과를 얻으셨다면 Day1의 실습은 마무리가 된 것입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Artificial Intelligence] 인공지능 의의와 정의, 발전 사항]]></title>
            <link>https://velog.io/@hang_geee/Artificial-Intelligence-%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5-%EC%9D%98%EC%9D%98%EC%99%80-%EC%A0%95%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%82%AC%ED%95%AD</link>
            <guid>https://velog.io/@hang_geee/Artificial-Intelligence-%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5-%EC%9D%98%EC%9D%98%EC%99%80-%EC%A0%95%EC%9D%98-%EB%B0%9C%EC%A0%84-%EC%82%AC%ED%95%AD</guid>
            <pubDate>Tue, 23 Aug 2022 14:41:54 GMT</pubDate>
            <description><![CDATA[<ul>
<li><p>인공지능이란?</p>
<ul>
<li>기계 지능을 다루는 컴퓨터 공학 분야</li>
<li>인간 같은 인지능력을 구현</li>
<li>추론, 문제 해결, 계획, 이해, 학습 그리고 패턴을 인식</li>
</ul>
</li>
<li><p>퍼셉트론 [Rosenblatt, 1958]</p>
<ul>
<li>학습을 통해 인식이 가능하다는 걸 최초로 보여줌</li>
<li>단일 신경을 많이 모방한 모델</li>
<li>input 여러개와 weight → 출력 (서로 곱한 다음에 더하는 내적을 통해 값을 구함)<ul>
<li>일정 역치 값이 넘으면 다음으로 신호 전달하는 등</li>
</ul>
</li>
</ul>
</li>
<li><p>XOR 문제는 퍼셉트론만으로는 풀 수 없다.</p>
<ul>
<li>2차원 위에 데이터를 올려서 흰돌 검은돌 구분</li>
<li>뭉쳐있으면 그걸 구분하는 선을 찾는 것은 쉬움</li>
<li>but, 검은돌 흰돌이 흩어져 있으면 직선 하나로 구분하기 힘듦</li>
<li><strong>XOR 하나로 이런 문제를 풀 수 없다</strong></li>
</ul>
</li>
<li><p><strong>LeNet-5 [Lecen et al., Proceedings of the IEEE 1998]</strong></p>
<ul>
<li>첫 번째 컨볼루션 기반 뉴럴넷</li>
<li>우편번호 인식에 큰 성공을 거둠</li>
<li>우편물 분류의 혁신</li>
</ul>
</li>
<li><p><strong>Convolutionoal Neural Networks의 재탄생</strong></p>
<ul>
<li>두 번째 재탄생 - 딥러닝의 혁신</li>
</ul>
</li>
<li><p><strong>AlexNet</strong></p>
<ul>
<li>ImageNet 챌린지 2012에서 큰 격차로 1등</li>
<li>인풋과 아웃풋, 학습만으로 훨씬 더 좋은 알고리즘을 개발</li>
<li>성공 이유<ul>
<li>빅데이터, 발전된 알고리즘, 연산 능력</li>
</ul>
</li>
</ul>
</li>
<li><p>기계학습 패러다임의 변화</p>
<ul>
<li>Machine Learning vs Deep Learning<ul>
<li>Machine Learning<ul>
<li>입력 → 특징 추출 → 분류 → 출력</li>
</ul>
</li>
<li>Deep Learning<ul>
<li>입력 → 특징 추출 &amp; 분류 → 출력</li>
</ul>
</li>
</ul>
</li>
<li>DL은 입력과 출력만 주면 알아서 특징 추출하고 분류 함</li>
</ul>
</li>
<li><p>딥러닝의 최근 성과</p>
<ul>
<li>자연어 처리 능력 비약적 발전 (GPT-3)</li>
<li>“인간은 선한가 악한가?”<ul>
<li>제 생각에는 인간은 선하기보다는 악합니다. 첫 번째로, 사람의 행동은 그들의 본성이 아니라, 사회와 문화와 같은 외적인 요인들의 결과로 나타나기 때문입니다. 두 번째로, 인간의 가치는 시간이 지남에 따라 꾸준하게 감소했기 때문입니다.</li>
</ul>
</li>
<li>논리 정연하게 말을 함</li>
<li>Art application<ul>
<li>styleGAN</li>
<li>가짜 얼굴을 만듦 → 초상권 x</li>
</ul>
</li>
<li>GPT-3를 활용하여 텍스트로부터 이미지 생성</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers] SQL 고득점 Kit - String, Date]]></title>
            <link>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-String-Date</link>
            <guid>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-String-Date</guid>
            <pubDate>Wed, 20 Jul 2022 17:57:45 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-1-동물-보호소에-들어온-동물-중-이름이-lucy-ella-pickle-rogan-sabrina-mitty인-동물의-아이디와-이름-성별-및-중성화-여부를-조회하는-sql-문을-작성해주세요">문제 1. 동물 보호소에 들어온 동물 중 이름이 Lucy, Ella, Pickle, Rogan, Sabrina, Mitty인 동물의 아이디와 이름, 성별 및 중성화 여부를 조회하는 SQL 문을 작성해주세요.</h3>
<h4 id="풀이">풀이</h4>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS
WHERE NAME = &#39;Lucy&#39; or NAME = &#39;Ella&#39; or NAME = &#39;Pickle&#39; or NAME = &#39;Rogan&#39; or Name = &#39;Sabrina&#39; or Name = &#39;Mitty&#39;</code></pre>
<h3 id="문제-2-보호소에-돌아가신-할머니가-기르던-개를-찾는-사람이-찾아왔습니다-이-사람이-말하길-할머니가-기르던-개는-이름에-el이-들어간다고-합니다-동물-보호소에-들어온-동물-이름-중-이름에-el이-들어가는-개의-아이디와-이름을-조회하는-sql문을-작성해주세요-이때-결과는-이름-순으로-조회해주세요-단-이름의-대소문자는-구분하지-않습니다">문제 2. 보호소에 돌아가신 할머니가 기르던 개를 찾는 사람이 찾아왔습니다. 이 사람이 말하길 할머니가 기르던 개는 이름에 &#39;el&#39;이 들어간다고 합니다. 동물 보호소에 들어온 동물 이름 중, 이름에 &quot;EL&quot;이 들어가는 개의 아이디와 이름을 조회하는 SQL문을 작성해주세요. 이때 결과는 이름 순으로 조회해주세요. 단, 이름의 대소문자는 구분하지 않습니다.</h3>
<h4 id="풀이-1">풀이</h4>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE LOWER(NAME) LIKE &#39;%el%&#39; AND ANIMAL_TYPE = &#39;Dog&#39;
ORDER BY NAME</code></pre>
<h3 id="문제-3-보호소의-동물이-중성화되었는지-아닌지-파악하려-합니다-중성화된-동물은-sex_upon_intake-컬럼에-neutered-또는-spayed라는-단어가-들어있습니다-동물의-아이디와-이름-중성화-여부를-아이디-순으로-조회하는-sql문을-작성해주세요-이때-중성화가-되어있다면-o-아니라면-x라고-표시해주세요">문제 3. 보호소의 동물이 중성화되었는지 아닌지 파악하려 합니다. 중성화된 동물은 SEX_UPON_INTAKE 컬럼에 &#39;Neutered&#39; 또는 &#39;Spayed&#39;라는 단어가 들어있습니다. 동물의 아이디와 이름, 중성화 여부를 아이디 순으로 조회하는 SQL문을 작성해주세요. 이때 중성화가 되어있다면 &#39;O&#39;, 아니라면 &#39;X&#39;라고 표시해주세요.</h3>
<h4 id="풀이-2">풀이</h4>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME,
    CASE
        WHEN (SEX_UPON_INTAKE LIKE &#39;%Neutered%&#39; OR SEX_UPON_INTAKE LIKE &#39;%Spayed%&#39;) THEN &#39;O&#39;
    ELSE &#39;X&#39;
    END AS &#39;중성화&#39;
FROM ANIMAL_INS</code></pre>
<h3 id="문제-4-입양을-간-동물-중-보호-기간이-가장-길었던-동물-두-마리의-아이디와-이름을-조회하는-sql문을-작성해주세요-이때-결과는-보호-기간이-긴-순으로-조회해야-합니다">문제 4. 입양을 간 동물 중, 보호 기간이 가장 길었던 동물 두 마리의 아이디와 이름을 조회하는 SQL문을 작성해주세요. 이때 결과는 보호 기간이 긴 순으로 조회해야 합니다.</h3>
<h4 id="풀이-3">풀이</h4>
<pre><code class="language-sql">SELECT I.ANIMAL_ID, I.NAME
FROM ANIMAL_INS as I
LEFT OUTER JOIN ANIMAL_OUTS as O
ON I.ANIMAL_ID = O.ANIMAL_ID
ORDER BY O.DATETIME - I.DATETIME DESC
LIMIT 2;</code></pre>
<h3 id="문제-5-animal_ins-테이블에-등록된-모든-레코드에-대해-각-동물의-아이디와-이름-들어온-날짜1를-조회하는-sql문을-작성해주세요-이때-결과는-아이디-순으로-조회해야-합니다">문제 5. ANIMAL_INS 테이블에 등록된 모든 레코드에 대해, 각 동물의 아이디와 이름, 들어온 날짜1를 조회하는 SQL문을 작성해주세요. 이때 결과는 아이디 순으로 조회해야 합니다.</h3>
<h4 id="풀이-4">풀이</h4>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME, DATE_FORMAT(DATETIME, &#39;%Y-%m-%d&#39;) AS &#39;날짜&#39;
FROM ANIMAL_INS
ORDER BY ANIMAL_ID</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers] SQL 고득점 Kit - JOIN]]></title>
            <link>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-JOIN</link>
            <guid>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-JOIN</guid>
            <pubDate>Wed, 20 Jul 2022 17:35:41 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-1-천재지변으로-인해-일부-데이터가-유실되었습니다-입양을-간-기록은-있는데-보호소에-들어온-기록이-없는-동물의-id와-이름을-id-순으로-조회하는-sql문을-작성해주세요">문제 1. 천재지변으로 인해 일부 데이터가 유실되었습니다. 입양을 간 기록은 있는데, 보호소에 들어온 기록이 없는 동물의 ID와 이름을 ID 순으로 조회하는 SQL문을 작성해주세요.</h3>
<h4 id="풀이">풀이</h4>
<pre><code class="language-sql">SELECT O.ANIMAL_ID, O.NAME
FROM ANIMAL_INS as I
RIGHT OUTER JOIN ANIMAL_OUTS as O
ON I.ANIMAL_ID = O.ANIMAL_ID
WHERE I.ANIMAL_ID IS NULL</code></pre>
<h3 id="문제-2-관리자의-실수로-일부-동물의-입양일이-잘못-입력되었습니다-보호-시작일보다-입양일이-더-빠른-동물의-아이디와-이름을-조회하는-sql문을-작성해주세요-이때-결과는-보호-시작일이-빠른-순으로-조회해야합니다">문제 2. 관리자의 실수로 일부 동물의 입양일이 잘못 입력되었습니다. 보호 시작일보다 입양일이 더 빠른 동물의 아이디와 이름을 조회하는 SQL문을 작성해주세요. 이때 결과는 보호 시작일이 빠른 순으로 조회해야합니다.</h3>
<h4 id="풀이-1">풀이</h4>
<pre><code class="language-sql">SELECT I.ANIMAL_ID, I.NAME
FROM ANIMAL_INS as I
INNER JOIN ANIMAL_OUTS as O
ON I.ANIMAL_ID = O.ANIMAL_ID
WHERE O.DATETIME &lt; I.DATETIME
ORDER BY I.DATETIME</code></pre>
<h3 id="문제-3-아직-입양을-못-간-동물-중-가장-오래-보호소에-있었던-동물-3마리의-이름과-보호-시작일을-조회하는-sql문을-작성해주세요-이때-결과는-보호-시작일-순으로-조회해야-합니다">문제 3. 아직 입양을 못 간 동물 중, 가장 오래 보호소에 있었던 동물 3마리의 이름과 보호 시작일을 조회하는 SQL문을 작성해주세요. 이때 결과는 보호 시작일 순으로 조회해야 합니다.</h3>
<h4 id="풀이-2">풀이</h4>
<pre><code class="language-sql">
SELECT I.NAME, I.DATETIME
FROM ANIMAL_INS as I
LEFT OUTER JOIN ANIMAL_OUTS as O
ON I.ANIMAL_ID = O.ANIMAL_ID
WHERE O.DATETIME IS NULL
ORDER BY I.DATETIME
LIMIT 3;</code></pre>
<h3 id="문제-4-보호소에서-중성화-수술을-거친-동물-정보를-알아보려-합니다-보호소에-들어올-당시에는-중성화1되지-않았지만-보호소를-나갈-당시에는-중성화된-동물의-아이디와-생물-종-이름을-조회하는-아이디-순으로-조회하는-sql-문을-작성해주세요">문제 4. 보호소에서 중성화 수술을 거친 동물 정보를 알아보려 합니다. 보호소에 들어올 당시에는 중성화1되지 않았지만, 보호소를 나갈 당시에는 중성화된 동물의 아이디와 생물 종, 이름을 조회하는 아이디 순으로 조회하는 SQL 문을 작성해주세요.</h3>
<h4 id="풀이-3">풀이</h4>
<pre><code class="language-sql">SELECT I.ANIMAL_ID, I.ANIMAL_TYPE, I.NAME
FROM ANIMAL_INS as I
LEFT OUTER JOIN ANIMAL_OUTS as O
ON I.ANIMAL_ID = O.ANIMAL_ID
WHERE I.SEX_UPON_INTAKE != O.SEX_UPON_OUTCOME</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers] SQL 고득점 Kit - IS NULL]]></title>
            <link>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-IS-NULL</link>
            <guid>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-IS-NULL</guid>
            <pubDate>Wed, 20 Jul 2022 16:42:59 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-1-동물-보호소에-들어온-동물-중-이름이-없는-채로-들어온-동물의-id를-조회하는-sql-문을-작성해주세요-단-id는-오름차순-정렬되어야-합니다">문제 1. 동물 보호소에 들어온 동물 중, 이름이 없는 채로 들어온 동물의 ID를 조회하는 SQL 문을 작성해주세요. 단, ID는 오름차순 정렬되어야 합니다.</h3>
<h4 id="풀이">풀이</h4>
<pre><code class="language-sql">SELECT ANIMAL_ID
FROM ANIMAL_INS
WHERE NAME IS NULL</code></pre>
<h3 id="문제-2-동물-보호소에-들어온-동물-중-이름이-있는-동물의-id를-조회하는-sql-문을-작성해주세요-단-id는-오름차순-정렬되어야-합니다">문제 2. 동물 보호소에 들어온 동물 중, 이름이 있는 동물의 ID를 조회하는 SQL 문을 작성해주세요. 단, ID는 오름차순 정렬되어야 합니다.</h3>
<h4 id="풀이-1">풀이</h4>
<pre><code class="language-sql">SELECT ANIMAL_ID
FROM ANIMAL_INS
WHERE NAME IS NOT NULL</code></pre>
<h3 id="문제-3-입양-게시판에-동물-정보를-게시하려-합니다-동물의-생물-종-이름-성별-및-중성화-여부를-아이디-순으로-조회하는-sql문을-작성해주세요-이때-프로그래밍을-모르는-사람들은-null이라는-기호를-모르기-때문에-이름이-없는-동물의-이름은-no-name으로-표시해-주세요">문제 3. 입양 게시판에 동물 정보를 게시하려 합니다. 동물의 생물 종, 이름, 성별 및 중성화 여부를 아이디 순으로 조회하는 SQL문을 작성해주세요. 이때 프로그래밍을 모르는 사람들은 NULL이라는 기호를 모르기 때문에, 이름이 없는 동물의 이름은 &quot;No name&quot;으로 표시해 주세요.</h3>
<h4 id="풀이-2">풀이</h4>
<pre><code class="language-sql">SELECT ANIMAL_TYPE, IFNULL(NAME,&#39;No name&#39;) as NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers] SQL 고득점 Kit - GROUP BY]]></title>
            <link>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-GROUP-BY</link>
            <guid>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-GROUP-BY</guid>
            <pubDate>Sun, 17 Jul 2022 17:29:42 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-1동물-보호소에-들어온-동물-중-고양이와-개가-각각-몇-마리인지-조회하는-sql문을-작성해주세요-이때-고양이를-개보다-먼저-조회해주세요">문제 1.동물 보호소에 들어온 동물 중 고양이와 개가 각각 몇 마리인지 조회하는 SQL문을 작성해주세요. 이때 고양이를 개보다 먼저 조회해주세요.</h3>
<h3 id="풀이">풀이</h3>
<pre><code class="language-sql">SELECT ANIMAL_TYPE, COUNT(*) AS count
FROM ANIMAL_INS
GROUP BY ANIMAL_TYPE
ORDER BY ANIMAL_TYPE;</code></pre>
<p>ORDER BY를 쓰지 않아도 고양이가 개보다 먼저 조회되지만 추가 해줬음.
<code>GROUP BY를 통해 세분화 가능</code></p>
<h3 id="문제-2-동물-보호소에-들어온-동물-이름-중-두-번-이상-쓰인-이름과-해당-이름이-쓰인-횟수를-조회하는-sql문을-작성해주세요-이때-결과는-이름이-없는-동물은-집계에서-제외하며-결과는-이름-순으로-조회해주세요">문제 2. 동물 보호소에 들어온 동물 이름 중 두 번 이상 쓰인 이름과 해당 이름이 쓰인 횟수를 조회하는 SQL문을 작성해주세요. 이때 결과는 이름이 없는 동물은 집계에서 제외하며, 결과는 이름 순으로 조회해주세요.</h3>
<h3 id="풀이-1">풀이</h3>
<pre><code class="language-sql">SELECT NAME, COUNT(*) as COUNT
FROM ANIMAL_INS
GROUP BY NAME
HAVING COUNT(NAME) &gt;= 2
ORDER BY NAME;</code></pre>
<h3 id="문제-3-보호소에서는-몇-시에-입양이-가장-활발하게-일어나는지-알아보려-합니다-0900부터-1959까지-각-시간대별로-입양이-몇-건이나-발생했는지-조회하는-sql문을-작성해주세요-이때-결과는-시간대-순으로-정렬해야-합니다">문제 3. 보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 09:00부터 19:59까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.</h3>
<h3 id="풀이-2">풀이</h3>
<pre><code class="language-sql">SELECT HOUR(DATETIME) as HOUR, COUNT(*) as COUNT
FROM ANIMAL_OUTS
GROUP BY HOUR(DATETIME)
HAVING HOUR &gt;= 9 AND HOUR &lt;= 19
ORDER BY HOUR(DATETIME)</code></pre>
<h3 id="문제-4-보호소에서는-몇-시에-입양이-가장-활발하게-일어나는지-알아보려-합니다-0시부터-23시까지-각-시간대별로-입양이-몇-건이나-발생했는지-조회하는-sql문을-작성해주세요-이때-결과는-시간대-순으로-정렬해야-합니다">문제 4. 보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 0시부터 23시까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.</h3>
<pre><code class="language-sql">SET @num = -1;

SELECT (@num := @num + 1) as HOUR, 
(SELECT COUNT (*) FROM ANIMAL_OUTS WHERE HOUR(DATETIME)=@num) as COUNT
FROM ANIMAL_OUTS
WHERE @num&lt;23;</code></pre>
<p>넘 어려운 문제가 아닌가?..</p>
<h4 id="mysql에서-변수-사용-하기">MYSQL에서 변수 사용 하기</h4>
<p>SET @변수명 을 사용시 = 대입연산자를 사용한다
SELECT @변수명 을 사용시 := 과 같은 대입연산자를 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers] SQL 고득점 Kit - SUM, MAX, MIN]]></title>
            <link>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-SUM-MAX-MIN</link>
            <guid>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-SUM-MAX-MIN</guid>
            <pubDate>Sun, 17 Jul 2022 15:53:55 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-1-가장-최근에-들어온-동물은-언제-들어왔는지-조회하는-sql-문을-작성해주세요">문제 1. 가장 최근에 들어온 동물은 언제 들어왔는지 조회하는 SQL 문을 작성해주세요.</h3>
<pre><code class="language-sql">SELECT DATETIME AS 시간
FROM ANIMAL_INS
ORDER BY DATETIME DESC
LIMIT 1;</code></pre>
<p>max 함수 사용</p>
<pre><code class="language-sql">SELECT MAX(DATETIME) AS 시간
FROM ANIMAL_INS</code></pre>
<h3 id="문제-2-동물-보호소에-가장-먼저-들어온-동물은-언제-들어왔는지-조회하는-sql-문을-작성해주세요">문제 2. 동물 보호소에 가장 먼저 들어온 동물은 언제 들어왔는지 조회하는 SQL 문을 작성해주세요.</h3>
<pre><code class="language-sql">SELECT MIN(DATETIME) AS 시간
FROM ANIMAL_INS</code></pre>
<h3 id="문제-3-동물-보호소에-동물이-몇-마리-들어왔는지-조회하는-sql-문을-작성해주세요">문제 3. 동물 보호소에 동물이 몇 마리 들어왔는지 조회하는 SQL 문을 작성해주세요.</h3>
<pre><code class="language-sql">SELECT COUNT(ANIMAL_ID) AS count
FROM ANIMAL_INS</code></pre>
<h3 id="문제-4-동물-보호소에-들어온-동물의-이름은-몇-개인지-조회하는-sql-문을-작성해주세요-이때-이름이-null인-경우는-집계하지-않으며-중복되는-이름은-하나로-칩니다">문제 4. 동물 보호소에 들어온 동물의 이름은 몇 개인지 조회하는 SQL 문을 작성해주세요. 이때 이름이 NULL인 경우는 집계하지 않으며 중복되는 이름은 하나로 칩니다.</h3>
<pre><code class="language-sql">SELECT COUNT(DISTINCT NAME)
FROM ANIMAL_INS</code></pre>
<h5 id="중복-제거-distinct">중복 제거 <code>DISTINCT</code></h5>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programmers] SQL 고득점 Kit - SELECT]]></title>
            <link>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-SELECT</link>
            <guid>https://velog.io/@hang_geee/Programmers-SQL-%EA%B3%A0%EB%93%9D%EC%A0%90-Kit-SELECT</guid>
            <pubDate>Sun, 17 Jul 2022 15:44:07 GMT</pubDate>
            <description><![CDATA[<h1 id="문제-설명">문제 설명</h1>
<p>ANIMAL_INS 테이블은 동물 보호소에 들어온 동물의 정보를 담은 테이블입니다. ANIMAL_INS 테이블 구조는 다음과 같으며, <code>ANIMAL_ID</code>, <code>ANIMAL_TYPE</code>, <code>DATETIME</code>, <code>INTAKE_CONDITION</code>, <code>NAME</code>, <code>SEX_UPON_INTAKE</code>는 각각 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부를 나타냅니다.</p>
<p><img src="https://velog.velcdn.com/images/hang_geee/post/453c4a8e-f249-4a03-8cff-a70e7a8294ee/image.png" alt=""></p>
<h3 id="문제-1-동물-보호소에-들어온-모든-동물의-정보를-animal_id순으로-조회하는-sql문을-작성해주세요-sql을-실행하면-다음과-같이-출력되어야-합니다">문제 1. 동물 보호소에 들어온 모든 동물의 정보를 ANIMAL_ID순으로 조회하는 SQL문을 작성해주세요. SQL을 실행하면 다음과 같이 출력되어야 합니다.</h3>
<h3 id="풀이">풀이</h3>
<pre><code class="language-sql">SELECT *
FROM ANIMAL_INS
ORDER BY ANIMAL_ID;</code></pre>
<h3 id="문제-2-동물-보호소에-들어온-모든-동물의-이름과-보호-시작일을-조회하는-sql문을-작성해주세요-이때-결과는-animal_id-역순으로-보여주세요-sql을-실행하면-다음과-같이-출력되어야-합니다">문제 2. 동물 보호소에 들어온 모든 동물의 이름과 보호 시작일을 조회하는 SQL문을 작성해주세요. 이때 결과는 ANIMAL_ID 역순으로 보여주세요. SQL을 실행하면 다음과 같이 출력되어야 합니다.</h3>
<h3 id="풀이-1">풀이</h3>
<pre><code class="language-sql">SELECT NAME, DATETIME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID DESC;</code></pre>
<h3 id="문제-3-동물-보호소에-들어온-동물-중-아픈-동물1의-아이디와-이름을-조회하는-sql-문을-작성해주세요-이때-결과는-아이디-순으로-조회해주세요">문제 3. 동물 보호소에 들어온 동물 중 아픈 동물1의 아이디와 이름을 조회하는 SQL 문을 작성해주세요. 이때 결과는 아이디 순으로 조회해주세요.</h3>
<h3 id="풀이-2">풀이</h3>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION = &#39;Sick&#39;;</code></pre>
<h3 id="문제-4-동물-보호소에-들어온-동물-중-젊은-동물1의-아이디와-이름을-조회하는-sql-문을-작성해주세요-이때-결과는-아이디-순으로-조회해주세요">문제 4. 동물 보호소에 들어온 동물 중 젊은 동물1의 아이디와 이름을 조회하는 SQL 문을 작성해주세요. 이때 결과는 아이디 순으로 조회해주세요.</h3>
<h3 id="풀이-3">풀이</h3>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION != &#39;Aged&#39;;</code></pre>
<h3 id="문제-5-동물-보호소에-들어온-모든-동물의-아이디와-이름을-animal_id순으로-조회하는-sql문을-작성해주세요-sql을-실행하면-다음과-같이-출력되어야-합니다">문제 5. 동물 보호소에 들어온 모든 동물의 아이디와 이름을 ANIMAL_ID순으로 조회하는 SQL문을 작성해주세요. SQL을 실행하면 다음과 같이 출력되어야 합니다.</h3>
<h3 id="풀이-4">풀이</h3>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID ASC;</code></pre>
<h3 id="문제-6-동물-보호소에-들어온-모든-동물의-아이디와-이름-보호-시작일을-이름-순으로-조회하는-sql문을-작성해주세요-단-이름이-같은-동물-중에서는-보호를-나중에-시작한-동물을-먼저-보여줘야-합니다">문제 6. 동물 보호소에 들어온 모든 동물의 아이디와 이름, 보호 시작일을 이름 순으로 조회하는 SQL문을 작성해주세요. 단, 이름이 같은 동물 중에서는 보호를 나중에 시작한 동물을 먼저 보여줘야 합니다.</h3>
<h3 id="풀이-5">풀이</h3>
<pre><code class="language-sql">SELECT ANIMAL_ID, NAME, DATETIME
FROM ANIMAL_INS
ORDER BY NAME ASC, DATETIME DESC;</code></pre>
<h3 id="문제-7-동물-보호소에-가장-먼저-들어온-동물의-이름을-조회하는-sql-문을-작성해주세요">문제 7. 동물 보호소에 가장 먼저 들어온 동물의 이름을 조회하는 SQL 문을 작성해주세요.</h3>
<h3 id="풀이-6">풀이</h3>
<pre><code class="language-sql">SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME ASC
LIMIT 1;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ] 16171 나는 친구가 적다 (python)]]></title>
            <link>https://velog.io/@hang_geee/BOJ16171-%EB%82%98%EB%8A%94-%EC%B9%9C%EA%B5%AC%EA%B0%80-%EC%A0%81%EB%8B%A4-python</link>
            <guid>https://velog.io/@hang_geee/BOJ16171-%EB%82%98%EB%8A%94-%EC%B9%9C%EA%B5%AC%EA%B0%80-%EC%A0%81%EB%8B%A4-python</guid>
            <pubDate>Fri, 15 Jul 2022 14:22:37 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>친구가 적은 성민이는 수업에 결석해도 시험이나 과제에 대한 정보를 제대로 얻을 수 없었다. F 학점을 받을 위기까지 아슬아슬하게 결석일 수를 유지하던 성민이는, 어느 날 갑자기 영문도 모른 채 쪽지시험을 보게 되었다!</p>
<p>갑작스러운 쪽지 시험으로 마음이 급해진 성민이는 매직아이를 사용해 벼락치기를 하기로 한다.</p>
<p>성민이가 듣는 과목의 교과서는, 알파벳 소문자(a-z)와 알파벳 대문자(A-Z)로만 이루어져 있다. 성민이가 교과서에서 찾고자 하는 키워드도 역시 알파벳 소문자와 대문자로만 이루어져 있다. 하지만, 성민이에겐 큰 문제가 생겼다. 결석한 날의 수업 내용을 친구에게 빌려 필기를 하던 중, 교과서에 숫자(0-9)를 적어버린 것이다.</p>
<p>키워드를 찾기 힘들어 패닉에 빠진 성민이는 몇 안 되는 친구인 당신에게 도움을 요청했다. 성민이를 도와, 교과서에서 성민이가 찾고자 하는 키워드의 존재 여부를 알려주자.</p>
<h3 id="입력">입력</h3>
<p>첫 번째 줄에는 알파벳 소문자, 대문자, 숫자로 이루어진 문자열 S가 주어진다. (1 ≤ |S| ≤ 100) 두 번째 줄에는 성민이가 찾고자 하는 알파벳 소문자, 대문자로만 이루어진 키워드 문자열 K가 주어진다. (1 ≤ |K| ≤ 100).</p>
<p>단, 입력으로 들어오는 키워드 문자열 K의 길이는, 교과서의 문자열 S보다 짧거나 같다.</p>
<h3 id="출력">출력</h3>
<p>첫 번째 줄에 성민이가 찾고자 하는 키워드가 문자열 내에 존재하면 1, 존재하지 않으면 0을 출력한다.</p>
<h2 id="풀이">풀이</h2>
<h4 id="내-풀이">내 풀이</h4>
<pre><code class="language-python">note = input()

keyword = input()
note_without_num = &#39;&#39;

for s in note:
    if 48 &lt;= ord(s) &lt;= 57: # 숫자면
        pass
    else:
        note_without_num += s


if keyword in note_without_num:
    print(1)
else:
    print(0)</code></pre>
<h4 id="더-괜찮은-느낌의-풀이">더 괜찮은 느낌의 풀이</h4>
<pre><code>for s in note:
    if s.isalpha():
        note_without_num += s      </code></pre><p>isalpha()를 쓰고 싶었는데 기억이 나지 않았다!!</p>
<p>ord(0)이 48이고 ord(9)가 57이길래 위와 같은 범위를 세워서 숫자와 문자를 구분했다.</p>
<p>1학기에 isalpha(), isdigit()을 통해 문자인지 숫자인지 구분하는 것을 했었는데 또 까먹지 않기 위해 기록으로 남긴다.</p>
<h3 id="기억하자">기억하자!!</h3>
<p><code>isalpha() -&gt; 문자열이 문자인지 확인하는 메소드</code>
<code>isdigit() -&gt; 문자열이 숫자인지 확인하는 메소드</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Computer Science] 쿠키와 세션]]></title>
            <link>https://velog.io/@hang_geee/Computer-Science-%EC%BF%A0%ED%82%A4%EC%99%80-%EC%84%B8%EC%85%98</link>
            <guid>https://velog.io/@hang_geee/Computer-Science-%EC%BF%A0%ED%82%A4%EC%99%80-%EC%84%B8%EC%85%98</guid>
            <pubDate>Thu, 14 Jul 2022 08:24:48 GMT</pubDate>
            <description><![CDATA[<h1 id="cookie--session">Cookie &amp; Session</h1>
<h2 id="쿠키-cookie">쿠키 (Cookie)</h2>
<h4 id="쿠키란">쿠키란?</h4>
<ul>
<li>쿠키는 <code>클라이언트 로컬</code>에 저장되는 키와 값이 들어있는 작은 데이터 <code>파일</code></li>
<li>사용자 인증이 유효한 시간을 명시 가능</li>
<li>유효 시간이 정해지면 브라우저가 종료 되어도 인증 유지</li>
<li>클라이언트에 300개까지 쿠키 저장 가능, 하나의 도메인당 20개의 값만 가질 수 있음</li>
<li>하나의 쿠키값은 4KB까지 저장</li>
<li>Response Header에 Set-Cookie 속성을 사용하면 클라이언트에 쿠키 생성 가능</li>
<li>쿠키는 사용자가 따로 요청하지 않아도 브라우저가 Request 시에 Request Header를 넣어서 자동으로 서버에 전송</li>
</ul>
<h4 id="쿠키의-구성-요소">쿠키의 구성 요소</h4>
<ul>
<li>이름 : 각각의 쿠키를 구별하는 데 사용 되는 이름</li>
<li>값 : 쿠키의 이름과 관련된 값</li>
<li>유효 시간 : 쿠키의 유지 시간</li>
<li>도메인 : 쿠키를 전송할 도메인</li>
<li>경로 : 쿠키를 전송할 요청 경로</li>
</ul>
<h4 id="쿠키의-동작-방식">쿠키의 동작 방식</h4>
<ul>
<li>클라이언트가 페이지를 요청</li>
<li>서버에서 쿠키를 생성</li>
<li>HTTP 헤더에 쿠키를 포함시켜 응답</li>
<li>브라우저가 종료되어도 쿠키 만료 기간이 있다면 클라이언트에서 보관하고 있음</li>
<li>같은 요청을 할 경우 HTTP 헤더에 쿠키를 함께 보냄</li>
<li>서버에서 쿠키를 읽어 이전 상태 정보를 변경할 필요가 있을 때 쿠키를 업데이트하여 변경된 쿠키를 HTTP 헤더에 포함시켜 응답</li>
</ul>
<h4 id="쿠키의-사용-예시">쿠키의 사용 예시</h4>
<ul>
<li><code>&quot;아이디와 비밀번호를 저장하시겠습니까?&quot;</code></li>
<li><code>장바구니 기능</code></li>
<li><code>자동 로그인</code> <code>&quot;오늘 더 이상 이창을 보지 않음&quot;</code></li>
</ul>
<h2 id="세션-session">세션 (Session)</h2>
<h4 id="세션이란">세션이란?</h4>
<ul>
<li>세션은 쿠키를 기반하고 있지만, 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 세션은 서버 측에서 관리합니다.</li>
<li>서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하며 웹 브라우저가 서버에 접속해서 브라우저를 종료할 때까지 인증 상태를 유지</li>
<li>접속 시간에 제한 두어 일정 시간 응답이 없으면 정보가 유지되지 않게 설정이 가능<ul>
<li>SWEA 같은 경우가 이게 짧아서 로그아웃이 엄청 자주 되나 봅니다.</li>
</ul>
</li>
<li>사용자에 대한 정보를 서버에 두기 때문에 쿠키보다 보안에 좋음</li>
<li>But 사용자가 많아질수록 서버 메모리를 많이 차지하게 됨</li>
<li>동접자 수가 많은 웹사이트 경우 서버에 과부하 =&gt; 성능 저하의 요인</li>
<li>클라이언트가 Request를 보내면, 해당 서버의 엔진이 클라이언트에게 유일한 ID를 부여 == 세션 ID</li>
</ul>
<h4 id="세션의-동작-방식">세션의 동작 방식</h4>
<ul>
<li>클라이언트가 서버에 접속 시 세션 ID를 발급 받음</li>
<li>클라이언트는 세션 ID에 대해 쿠키를 사용해서 저장하고 가지고 있음</li>
<li>클라이언트는 서버에 요청할 때, 이 쿠키의 세션 ID를 같이 서버에 전달해서 요청</li>
<li>서버는 세션 ID를 전달 받아서 별다른 작업 없이 세션 ID로 세션에 있는 클라이언트 정보를 가져와서 사용</li>
<li>클라이언트 정보를 가지고 서버 요청을 처리하여 클라이언트에게 응답</li>
</ul>
<h4 id="세션의-특징">세션의 특징</h4>
<ul>
<li>각 클라이언트에게 고유 ID를 부여</li>
<li>세션 ID로 클라이언트를 구분해서 클라이언트의 요구에 맞는 서비스를 제공</li>
<li>보안 면에서 쿠키보다 우수</li>
<li>사용자가 많아질수록 서버 메모리를 많이 차지하게 됨</li>
</ul>
<h4 id="세션의-사용-예시">세션의 사용 예시</h4>
<ul>
<li><code>로그인과 같이 보안상 중요한 작업을 수행할 때 사용</code></li>
</ul>
<h3 id="쿠키와-세션-비교">쿠키와 세션 비교</h3>
<ul>
<li><p>정보가 저장되는 위치</p>
<ul>
<li>쿠키 - 클라이언트</li>
<li>세션 - 서버</li>
</ul>
</li>
<li><p>보안</p>
<ul>
<li>쿠키 - 클라이언트 로컬에 저장되기 때문에 변질 되거나 request에서 스니핑 당할 우려가 있어서 보안에 취약함</li>
<li>세션 - 쿠키를 이용해 sessionid만 저장하고 그것으로 구분해서 서버에서 처리하기 때문에 비교적 보안성이 좋다.</li>
</ul>
</li>
<li><p>라이프 사이클</p>
<ul>
<li>쿠키 - 만료 시간이 있지만 파일로 저장되기 때문에 브라우저를 종료해도 계속해서 정보가 남아 있을 수 있다. 만료 기간을 넉넉하게 잡는다면 쿠키 삭제할 때까지 유지도 가능</li>
<li>세션 - 만료 시간을 정할 수는 있지만 브라우저가 종료 되면 그와 관계 없이 삭제 됨.</li>
</ul>
</li>
<li><p>속도</p>
<ul>
<li>쿠키 - 정보를 가지고 있기 때문에 서버에 요청시 속도가 빠름</li>
<li>세션 - 정보가 서버에 있기 때문에 처리가 요구되어 비교적 느린 속도를 가짐</li>
</ul>
</li>
</ul>
<hr>
<h2 id="쿠키와-세션의-차이를-말씀해주세요">쿠키와 세션의 차이를 말씀해주세요</h2>
<ul>
<li>한 줄 답변<ul>
<li>쿠키와 세션의 가장 큰 차이점은 정보가 저장되는 위치입니다.
쿠키는 서버의 자원을 사용하지 않고 세션은 서버의 자원을 사용합니다.</li>
</ul>
</li>
</ul>
<h2 id="쿠키와-세션은-왜-사용하나요">쿠키와 세션은 왜 사용하나요?</h2>
<ul>
<li><p>한 줄 답변</p>
<ul>
<li>HTTP 프로토콜은 connectionless와 stateless 한 특성을 가지기 때문에 서버는 클라이언트가 누구인지 매번 확인해야합니다. 이러한 특성을 보완하기 위해 쿠키와 세션을 사용합니다.</li>
</ul>
</li>
</ul>
<h2 id="세션을-사용하는-것이-더-좋아보이는데-왜-쿠키를-사용하나요">세션을 사용하는 것이 더 좋아보이는데 왜 쿠키를 사용하나요?</h2>
<ul>
<li>한 줄 답변<ul>
<li>세션은 서버의 자원을 사용하기 때문에 무분별하게 만들다보면 서버의 메모리를 감당할 수 없어지고 속도가 느려질 수 있기 때문에 쿠키가 유리한 경우가 있습니다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ] 17281 야구 (python)]]></title>
            <link>https://velog.io/@hang_geee/BOJ-17281-%EC%95%BC%EA%B5%AC-python</link>
            <guid>https://velog.io/@hang_geee/BOJ-17281-%EC%95%BC%EA%B5%AC-python</guid>
            <pubDate>Mon, 04 Jul 2022 16:41:09 GMT</pubDate>
            <description><![CDATA[<p>분명 알고리즘 문제가 메인이 아니었는데 왜 이거만 올리고 있지..</p>
<h2 id="문제">문제</h2>
<p>⚾는 9명으로 이루어진 두 팀이 공격과 수비를 번갈아 하는 게임이다. 하나의 이닝은 공격과 수비로 이루어져 있고, 총 N이닝 동안 게임을 진행해야 한다. 한 이닝에 3아웃이 발생하면 이닝이 종료되고, 두 팀이 공격과 수비를 서로 바꾼다.</p>
<p>두 팀은 경기가 시작하기 전까지 타순(타자가 타석에 서는 순서)을 정해야 하고, 경기 중에는 타순을 변경할 수 없다. 9번 타자까지 공을 쳤는데 3아웃이 발생하지 않은 상태면 이닝은 끝나지 않고, 1번 타자가 다시 타석에 선다. 타순은 이닝이 변경되어도 순서를 유지해야 한다. 예를 들어, 2이닝에 6번 타자가 마지막 타자였다면, 3이닝은 7번 타자부터 타석에 선다.</p>
<p>공격은 투수가 던진 공을 타석에 있는 타자가 치는 것이다. 공격 팀의 선수가 1루, 2루, 3루를 거쳐서 홈에 도착하면 1점을 득점한다. 타자가 홈에 도착하지 못하고 1루, 2루, 3루 중 하나에 머물러있을 수 있다. 루에 있는 선수를 주자라고 한다. 이닝이 시작될 때는 주자는 없다.</p>
<p>타자가 공을 쳐서 얻을 수 있는 결과는 안타, 2루타, 3루타, 홈런, 아웃 중 하나이다. 각각이 발생했을 때, 벌어지는 일은 다음과 같다.</p>
<p>안타: 타자와 모든 주자가 한 루씩 진루한다.
2루타: 타자와 모든 주자가 두 루씩 진루한다.
3루타: 타자와 모든 주자가 세 루씩 진루한다.
홈런: 타자와 모든 주자가 홈까지 진루한다.
아웃: 모든 주자는 진루하지 못하고, 공격 팀에 아웃이 하나 증가한다.
한 야구팀의 감독 아인타는 타순을 정하려고 한다. 아인타 팀의 선수는 총 9명이 있고, 1번부터 9번까지 번호가 매겨져 있다. 아인타는 자신이 가장 좋아하는 선수인 1번 선수를 4번 타자로 미리 결정했다. 이제 다른 선수의 타순을 모두 결정해야 한다. 아인타는 각 선수가 각 이닝에서 어떤 결과를 얻는지 미리 알고 있다. 가장 많은 득점을 하는 타순을 찾고, 그 때의 득점을 구해보자.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 이닝 수 N(2 ≤ N ≤ 50)이 주어진다. 둘째 줄부터 N개의 줄에는 각 선수가 각 이닝에서 얻는 결과가 1번 이닝부터 N번 이닝까지 순서대로 주어진다. 이닝에서 얻는 결과는 9개의 정수가 공백으로 구분되어져 있다. 각 결과가 의미하는 정수는 다음과 같다.</p>
<p>안타: 1
2루타: 2
3루타: 3
홈런: 4
아웃: 0
각 이닝에는 아웃을 기록하는 타자가 적어도 한 명 존재한다.</p>
<h3 id="출력">출력</h3>
<p>아인타팀이 얻을 수 있는 최대 점수를 출력한다.</p>
<p>처음 생각했던 점수 산정 방법
<img src="https://velog.velcdn.com/images/hang_geee/post/b52853d9-4303-44a5-896f-2c16d4dd2e3e/image.png" alt=""></p>
<h2 id="풀이1---시간-초과">풀이1 - 시간 초과</h2>
<h3 id="점수산정-방식">점수산정 방식</h3>
<p>=&gt; base라는 deque를 만들어서 진루타를 칠 때마다 앞에 추가해주고 뒤에서 pop한 값을 더해줬다.</p>
<pre><code class="language-python">import sys
from itertools import permutations
from collections import deque

input = sys.stdin.readline
inning = int(input())
hitting = [list(map(int, input().split())) for _ in range(inning)]

max_score = 0
def game(line_ups):
    idx = 0
    score = 0
    for each_inning in hitting:
        out = 0
        base = deque([0, 0, 0])
        while True:
            if out == 3:
                break
            if each_inning[line_ups[idx]] == 0:
                out += 1
            elif each_inning[line_ups[idx]] == 1:
                base.appendleft(1)
                score += base.pop()
            elif each_inning[line_ups[idx]] == 2:
                base.appendleft(1)
                base.appendleft(0)
                score += base.pop()
                score += base.pop()
            elif each_inning[line_ups[idx]] == 3:
                base.appendleft(1)
                base.appendleft(0)
                base.appendleft(0)
                score += base.pop()
                score += base.pop()
                score += base.pop()
            elif each_inning[line_ups[idx]] == 4:
                base.appendleft(1)
                base.appendleft(0)
                base.appendleft(0)
                base.appendleft(0)
                score += base.pop()
                score += base.pop()
                score += base.pop()
                score += base.pop()
            idx = (idx + 1) % 9
    return score

for line_ups in permutations(range(1, 9), 8):
    line_ups = list(line_ups[:3]) + [0] + list(line_ups[3:])
    max_score = max(max_score, game(line_ups))

print(max_score)</code></pre>
<p>오늘도 가차없이 시간초과를 때려주는 냉정한 백준</p>
<hr>
<h2 id="풀이2---deque말고-값으로-대체">풀이2 - deque말고 값으로 대체</h2>
<pre><code class="language-python">import sys
from itertools import permutations
from collections import deque

input = sys.stdin.readline
inning = int(input())
hitting = [list(map(int, input().split())) for _ in range(inning)]

max_score = 0
def game(line_ups):
    idx = 0
    score = 0
    for each_inning in hitting:
        out = 0
        # base = deque([0, 0, 0])
        b1, b2, b3 = 0, 0, 0
        while True:
            if out == 3:
                break
            if each_inning[line_ups[idx]] == 0:
                out += 1
            elif each_inning[line_ups[idx]] == 1:
                # base.appendleft(1)
                # score += base.pop()

                score += b3
                b1, b2, b3 = 1, b1, b2
            elif each_inning[line_ups[idx]] == 2:
                # base.appendleft(1)
                # base.appendleft(0)
                # score += base.pop()
                # score += base.pop()
                score += (b2 + b3)
                b1, b2, b3 = 0, 1, b1
            elif each_inning[line_ups[idx]] == 3:
                # base.appendleft(1)
                # base.appendleft(0)
                # base.appendleft(0)
                # score += base.pop()
                # score += base.pop()
                # score += base.pop()

                score += (b1 + b2 + b3)
                b1, b2, b3 = 0, 0, 1
            elif each_inning[line_ups[idx]] == 4:
                # base.appendleft(1)
                # base.appendleft(0)
                # base.appendleft(0)
                # base.appendleft(0)
                # score += base.pop()
                # score += base.pop()
                # score += base.pop()
                # score += base.pop()
                score += (1 + b1 + b2 + b3)
                b1, b2, b3 = 0, 0, 0
            idx = (idx + 1) % 9
    return score

for line_ups in permutations(range(1, 9), 8):
    line_ups = list(line_ups[:3]) + [0] + list(line_ups[3:])
    max_score = max(max_score, game(line_ups))

print(max_score)</code></pre>
<p>기존의 코드를 그대로 두고 base를 deque로 했던 것을 그냥 값(?)으로 바꿔줬다.
deque가 O(1)의 시간복잡도를 가지고 있기 때문에 별차이 없을 것이라 생각했는데 그렇지 않았다.</p>
<hr>
<h2 id="itertools-사용하기">itertools 사용하기</h2>
<p><a href="https://docs.python.org/ko/3.8/library/itertools.html">itertools_ python 공식문서</a></p>
<h3 id="itertools란">itertools란?</h3>
<p><code>효율적인 루핑을 위한 이터레이터를 만드는 함수</code>라고 써져있다.
itertools에는 수많은 이터레이터가 존재하지만 그 중에서 자주 쓰이는 것 같은 combination과 permutations에 대해 짚고 넘어가보자!</p>
<p>이게 느리다는 것으로 알고 있어서 그냥 무시하고 지나갔었는데 알고 있으면 확실히 이런 문제에 도움이 될 것이라는 생각이 든다!!</p>
<p>처음에 이 문제를 접했을 때 순열로 풀어야겠다는 생각은 했는데 막상 순열을 구현하기가 어려울 때 파이썬의 장점을 가장 극대화할 수 있는 무기가 아닐까? (이래서 코테는 파이썬으로 하라고 하나보다)</p>
<p>combination 즉, 조합이다!
순열과 조합을 배웠다면 뭔지 들어보기는 했을 것이다.
조합은 A,B와 B,A를 같은 것으로 본다. 즉, 중복을 허용하지 않는다고 생각하면 된다.</p>
<p>순서가 중요하면 아래 permutation, 순열을 사용하면 된다!
가령 1,2,3과 1,3,2의 경우 내용물은 똑같지만 순서가 다르다.
permutation의 경우 3가지 원소에서 순서를 정하기 위해
1,2,3 / 1,3,2 / 2,1,3 / 2,3,1 / 3,1,2 / 3,2,1/
이런식으로 모두 같은 원소지만 순서가 다른 것들도 다 나오게 한다.</p>
<p>반대로 조합의 경우 3가지 원소 중에 3가지를 모두를 뽑는 방법은
1,2,3 /
단 하나만 존재하는 것이다! 이게 순열과 조합의 차이이.</p>
<p>각설하고, 사용법은 이렇다.</p>
<h3 id="itertools-활용---combination">itertools 활용 -&gt; combination</h3>
<pre><code class="language-python">from itertools import combinations
example = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]
cb = list(combinations(example, 2))
print(cb)
[(&#39;a&#39;, &#39;b&#39;), (&#39;a&#39;, &#39;c&#39;), (&#39;b&#39;, &#39;c&#39;)]</code></pre>
<p>example 내에 있는 3개의 원소 중에 2개를 고르는 조합이다.
3C1이니까 3개가 나오는 것은..설명하지 않겠다.</p>
<h3 id="itertools-활용---permutation">itertools 활용 -&gt; permutation</h3>
<pre><code class="language-python">from itertools import permutations

example = [1, 2, 3]
perm = list(permutations(example, 2))
print(perm)
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]</code></pre>
<p>순열의 경우 모든 줄세우기가 가능한 경우가 다 나온다.</p>
<p>3개의 원소 중 2개를 뽑아 줄을 세우는 경우이기 때문에
1,2를 뽑더라도 1,2만 나오는 것이 아닌 2,1도 포함 된다.</p>
<hr>
<h2 id="결론">결론</h2>
<p>itertools 사용법을 익히면 분명 도움이 될 것이다!! (코테 한정)</p>
<ul>
<li>꼭 queue를 사용하는 것을 고집하지 말고 변수로 대체 가능한지 생각해보자.</li>
<li>유연한 사고</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ] 17070 파이프 옮기기 1 (python)]]></title>
            <link>https://velog.io/@hang_geee/BOJ-17070-%ED%8C%8C%EC%9D%B4%ED%94%84-%EC%98%AE%EA%B8%B0%EA%B8%B0-1-python</link>
            <guid>https://velog.io/@hang_geee/BOJ-17070-%ED%8C%8C%EC%9D%B4%ED%94%84-%EC%98%AE%EA%B8%B0%EA%B8%B0-1-python</guid>
            <pubDate>Sun, 03 Jul 2022 12:38:25 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의 번호이고, 행과 열의 번호는 1부터 시작한다. 각각의 칸은 빈 칸이거나 벽이다.</p>
<p>오늘은 집 수리를 위해서 파이프 하나를 옮기려고 한다. 파이프는 아래와 같은 형태이고, 2개의 연속된 칸을 차지하는 크기이다.</p>
<p>파이프는 회전시킬 수 있으며, 아래와 같이 3가지 방향이 가능하다.</p>
<p>파이프는 매우 무겁기 때문에, 유현이는 파이프를 밀어서 이동시키려고 한다. 벽에는 새로운 벽지를 발랐기 때문에, 파이프가 벽을 긁으면 안 된다. 즉, 파이프는 항상 빈 칸만 차지해야 한다.</p>
<p>파이프를 밀 수 있는 방향은 총 3가지가 있으며, →, ↘, ↓ 방향이다. 파이프는 밀면서 회전시킬 수 있다. 회전은 45도만 회전시킬 수 있으며, 미는 방향은 오른쪽, 아래, 또는 오른쪽 아래 대각선 방향이어야 한다.</p>
<p>파이프가 가로로 놓여진 경우에 가능한 이동 방법은 총 2가지, 세로로 놓여진 경우에는 2가지, 대각선 방향으로 놓여진 경우에는 3가지가 있다.</p>
<p>아래 그림은 파이프가 놓여진 방향에 따라서 이동할 수 있는 방법을 모두 나타낸 것이고, 꼭 빈 칸이어야 하는 곳은 색으로 표시되어져 있다.</p>
<p>가장 처음에 파이프는 (1, 1)와 (1, 2)를 차지하고 있고, 방향은 가로이다. 파이프의 한쪽 끝을 (N, N)로 이동시키는 방법의 개수를 구해보자.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 집의 크기 N(3 ≤ N ≤ 16)이 주어진다. 둘째 줄부터 N개의 줄에는 집의 상태가 주어진다. 빈 칸은 0, 벽은 1로 주어진다. (1, 1)과 (1, 2)는 항상 빈 칸이다.</p>
<h3 id="출력">출력</h3>
<p>첫째 줄에 파이프의 한쪽 끝을 (N, N)으로 이동시키는 방법의 수를 출력한다. 이동시킬 수 없는 경우에는 0을 출력한다. 방법의 수는 항상 1,000,000보다 작거나 같다.</p>
<h2 id="풀이">풀이</h2>
<h3 id="bfs---시간-초과-70">bfs -&gt; 시간 초과 (70%)</h3>
<pre><code class="language-python">from collections import deque
import sys
input = sys.stdin.readline

N = int(input())

arr = [list(map(int, input().split())) for _ in range(N)]

cnt = 0

&#39;&#39;&#39;
direction
0 == 가로
1 == 대각선
2 == 세로
&#39;&#39;&#39;
def bfs(si, sj, direction):
    global cnt
    q = deque()
    q.append((si, sj, direction))

    while q:
        ci, cj, dir = q.popleft()
        if ci == N-1 and cj == N-1:
            cnt += 1
            continue
        if dir == 0: # 가로 방향일 때
            ni, nj = ci+0, cj+1 # 가로로 이동
            if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N and arr[ni][nj] == 0:
                q.append((ni, nj, 0))
            ni, nj = ci+1, cj+1 # 대각선으로 이동
            if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N and arr[ni][nj] == 0 and arr[ci+1][cj] == 0 and arr[ci][cj+1] == 0:
                q.append((ni, nj, 1))
        elif dir == 1: # 대각선 방향일 때
            ni, nj = ci+0, cj+1 # 가로로 이동
            if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N and arr[ni][nj] == 0:
                q.append((ni, nj, 0))
            ni, nj = ci+1, cj+1 # 대각선으로 이동
            if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N and arr[ni][nj] == 0 and arr[ci+1][cj] == 0 and arr[ci][cj+1] == 0:
                q.append((ni, nj, 1))
            ni, nj = ci+1, cj+0 # 세로로 이동
            if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N and arr[ni][nj] == 0:
                q.append((ni, nj, 2))
        elif dir == 2:
            ni, nj = ci+1, cj # 세로로 이동
            if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N and arr[ni][nj] == 0:
                q.append((ni, nj, 2))
            ni, nj = ci+1, cj+1 # 대각선으로 이동
            if 0&lt;=ni&lt;N and 0&lt;=nj&lt;N and arr[ni][nj] == 0 and arr[ci+1][cj] == 0 and arr[ci][cj+1] == 0:
                q.append((ni, nj, 1))

bfs(0, 1, 0)

print(cnt)</code></pre>
<p>위는 bfs로 접근한 풀이다.</p>
<p>처음에는 deque을 안 써서 시간초과가 났나 싶었는데</p>
<p>deque와 sys.stdin.readline을 해도 시간 초과.. ㅠㅠ</p>
<p>조금 찾아보니 dfs(재귀)를 활용한 풀이는 시간 초과가 나지 않는다 해서 dfs로도 풀었다.</p>
<h3 id="dfs를-활용한-풀이">DFS를 활용한 풀이</h3>
<pre><code class="language-python">from collections import deque
import sys
input = sys.stdin.readline

N = int(input())

arr = [list(map(int, input().split())) for _ in range(N)]

cnt = 0

&#39;&#39;&#39;
direction
0 == 가로
1 == 세로
2 == 대각선
&#39;&#39;&#39;
def dfs(si, sj, direction):
    global cnt
    if si == N-1 and sj == N-1:
        cnt += 1
    if direction == 0: # 가로
        if sj + 1 &lt; N and arr[si][sj+1] == 0:
            dfs(si, sj+1, 0)
        if si + 1 &lt; N and sj + 1 &lt; N:
            if arr[si][sj+1] == 0 and arr[si+1][sj+1] == 0 and arr[si+1][sj] == 0:
                dfs(si+1, sj+1, 2) # 대각선으로 변경
    elif direction == 1: # 세로
        if si + 1 &lt; N and arr[si+1][sj] == 0:
            dfs(si+1, sj, 1)
        if si + 1 &lt; N and sj + 1 &lt; N:
            if arr[si+1][sj+1] == 0 and arr[si][sj+1] == 0 and arr[si+1][sj] == 0:
                dfs(si+1, sj+1, 2)
    elif direction == 2: # 대각선
        if sj + 1 &lt; N and arr[si][sj+1] == 0:
            dfs(si, sj+1, 0)
        if si + 1 &lt; N and arr[si+1][sj] == 0:
            dfs(si+1, sj, 1)
        if si + 1 &lt; N and sj + 1 &lt; N:
            if arr[si+1][sj+1] == 0 and arr[si+1][sj] == 0 and arr[si][sj+1] == 0:
                dfs(si+1, sj+1, 2)

dfs(0, 1, 0)
print(cnt)</code></pre>
<p>거의 모든 그래프 문제를 BFS로만 풀어서 DFS는 오랜만에 적용해봤다.</p>
<p>보통 BFS가 더 빠르다고 알고 있었는데 DFS는 시간 초과가 안 나서.. 좀 잘못 알고 있는 듯 하다.</p>
<p>이 부분은 따로 또 공부해서 포스팅하면 좋을 것 같다!!</p>
<p>어떻게 시간을 줄이면 좋을지와 DP 풀이도 추가해서 올리도록 하겠다.</p>
<hr>
<p>문제 풀이 원리는 간단하다.</p>
<p>가로는 가로 방향과 대각선 방향만 가능하고
세로는 세로 방향과 대각선 방향
대각선은 가로 세로 대각선 방향으로 이동이 가능하다.</p>
<p>모든 경우에 이동할 칸이 0이어야 하고 대각선 방향의 경우는 이동할 방향과 그 방향의 위쪽, 왼쪽이 0인지 체크해주고 이동하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[BOJ] 20413 MVP 다이아몬드 (python)]]></title>
            <link>https://velog.io/@hang_geee/BOJ-20413-MVP-%EB%8B%A4%EC%9D%B4%EC%95%84%EB%AA%AC%EB%93%9C-python</link>
            <guid>https://velog.io/@hang_geee/BOJ-20413-MVP-%EB%8B%A4%EC%9D%B4%EC%95%84%EB%AA%AC%EB%93%9C-python</guid>
            <pubDate>Mon, 27 Jun 2022 14:41:17 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>입력 제한 외 난이도에 따른 문제의 차이는 없다.</p>
<p>상민이는 게임 단풍잎이야기에 과금을 즐겨 한다. 단풍잎이야기에는 과금액에 따라 혜택을 제공하는 &#39;MVP 등급&#39;이 존재한다.</p>
<p>MVP 등급은 브론즈(B), 실버(S), 골드(G), 플래티넘(P), 다이아몬드(D)로 총 다섯 등급이 있으며, 현재 달과 지난달, 즉 현재 달을 포함한 최근 2개월간의 과금액으로 결정된다.</p>
<p>단, 단풍잎이야기에는 과도한 과금을 막기 위해 &#39;최대 과금 한도&#39;가 있어 한 달에 최대 다이아몬드 등급 기준액 까지만 과금할 수 있으며, 만원 단위로만 과금이 가능하다.</p>
<p>MVP 등급은 해당 달이 끝날 때 계산되어 책정된다. 예를 들어 아래의 표와 같은 등급 기준액을 따르고 1월에 게임을 시작한 상민이가 1월에 30만, 2월에 20만, 3월에 50만 원을 과금했다면 1월(30만)과 2월(30+20=50만)에는 실버 등급, 3월(20+50=70만)에는 골드 등급으로 책정된다.</p>
<p>MVP 등급(표기)    등급 기준액    2개월 간의 과금액
브론즈(B)    0만 원    0 원 ~ 29만 원
실버(S)    30만 원    30만 원 ~ 59만 원
골드(G)    60만 원    60만 원 ~ 89만 원
플래티넘(P)    90만 원    90만 원 ~ 149만 원
다이아몬드(D)    150만 원    150만 원 이상
&lt;표1&gt; 위 예시의 등급 기준표 (예제1)</p>
<p>상민이는 게임을 시작하고 N개월 동안 수많은 현금을 과금해왔다. 상민이는 이 사실을 자신의 여자친구에만큼은 철저히 비밀로 하고 있었다. 상민이의 여자친구는 상민이가 게임에 과금하는 것을 매우 싫어했기 때문이다. 그러던 어느 날 문제가 발생했다. 상민이의 여자친구에게 N개월간의 MVP 등급 기록이 유출된 것이다!</p>
<p>상민이의 여자친구는 상민의 과금액을 역추적하기 위해 당신에게 부탁했다.</p>
<p>상민이의 여자친구: 상민이가 게임에 최대 얼마나 과금한건지 알려줘.</p>
<p>둘 사이에 어떤 일이 벌어질지는 모르겠지만, 당신은 상민이의 여자친구를 위한 프로그램을 작성해야만 한다.</p>
<h3 id="입력">입력</h3>
<p>첫 번째 줄에는 게임을 플레이 한 개월수 N이 주어진다.</p>
<p>두 번째 줄에는 실버, 골드, 플래티넘, 다이아몬드 등급 기준액 s, g, p, d가 만원 단위로 순서대로 주어진다. 브론즈 등급 기준액은 0 원이다.</p>
<p>세 번째 줄에는 게임을 플레이 한 첫 번째 달부터 N 번째 달까지의 MVP 등급이 등급 표기대로 주어진다. 기록과 같은 MVP 등급 달성이 불가능한 경우는 주어지지 않는다.</p>
<h3 id="출력">출력</h3>
<p>입력된 MVP 등급을 달성하기 위한 최대 누적 과금액을 만원 단위로 출력한다.</p>
<h3 id="제한">제한</h3>
<p>1 ≤ N ≤ 36</p>
<p>0 &lt; s &lt; g &lt; p &lt; d ≤ 500</p>
<p>상민이가 한번 달성한 MVP 등급은 줄어들지 않는다.</p>
<hr>
<h2 id="풀이">풀이</h2>
<pre><code class="language-python">N = int(input())
standards = list(map(int, input().split()))
grades = input()

last = 0 # 지난 달 과금액
now = 0 # 이번 달 과금액
cnt = 0 # 과금액 최대 합

for grade in grades:
    if grade == &#39;B&#39;:
        now = standards[0]-1-last
        cnt += now
    elif grade == &#39;S&#39;:
        now = standards[1] - 1 - last
        cnt += now

    elif grade == &#39;G&#39;:
        now = standards[2] - 1 - last
        cnt += now

    elif grade == &#39;P&#39;:
        now = standards[3] - 1 - last
        cnt += now

    elif grade == &#39;D&#39;:
        now = standards[3]
        cnt += now
    last = now
print(cnt)</code></pre>
<p>총 두 달의 과금액을 더해주는 간단한 구현(?) 그리디(?) 문제였다.</p>
<p>지난 달과 이번 달의 과금액을 계속 갱신해주면서 과금액의 최댓값을 구해야하므로</p>
<p>다음 grade로 넘어가기 직전까지 금액이 최대 과금액이다.</p>
<p>for문 마지막에 last 값을 now로 갱신해주면서 계속 cnt에 더해주는 방식으로 구했다.</p>
<p>Diamond 등급의 경우 다이아몬드 등급 기준액까지만 과금할 수 있기 때문에 now를 standards[3]으로 정확하게 더해준다. (이 값보다 더 많이 과금할 수 없음)</p>
<p>Diamond 등급이 연속된 달에는 최대 과금액을 구한다면 매달 Diamond 기준 금액을 더하면 되고 최솟값을 구한다면 Diamond 기준 금액과 0을 번갈아가며 더해주면 될 것이다.</p>
<ul>
<li>신한은행 코딩테스트 1번 문제와 유사한 문제라고 나와있어서 풀어보게 되었다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>