• transformer 구조을 알기 위해서는 attention is all you need라는 논문을 보면된다.
  • transformer 구조는 아래그림과 같다.

 

  • 여기서 정리할것들
    • self attention
    • multi head attention
    • feed forward
    • add & Norm

 

1. Self Attention

 

참조 (아래 더보기 클릭)

  • 위의 구조가 self-attention의 핵심구조이다.
  • (MASK 모듈은 생성형 AI에 주로 쓰이니 생략해도 된다고 함)

 

<self attention 설명>

  • embedding_dimension이 d_model
  • I love you가 입력 x 이고  가로는 d_m or d_model이라고 부를거고 세로는 T개라고 명명하겠음
  • wq,wk,wv는 파라미터
  • Q,K,V는 X(입력벡터시퀀스)에 WQ,Wk,WV를 곱해서 구해준다.
  • WQ,Wk,WV는 Task(예: 기계 번역)를 가장 잘 수행하는 방향으로 학습 과정에서 업데이트됨
  • QK^T를 곱한 이유는 각 단어와 단어간의 상관관계를 보기위해서
    • Q의 (0,0) K의 (0,0)를 곱한숫자는 I와 I간의 상관관계가 어느정도인지 나타낸것과 같다고 볼 수 있다.
    • dk^1/2를 나눠주는 이유는 숫자가 극단적으로 갈수있는것을 예방하여 smoothing 한것과 동일하게 이해하면 된다
  • softmax를 적용한이유는 0-1사이의 숫자로 나타내주기위함
  • softmax(QK^T)를 해준다음 V를 곱한것의 의미는
    • I love you라는 문장에 각 i,love,you와의 상관관계를 적용해준것과 같다.
    • 예를들어서 배를 먹었더니 배가 아프다 라는 문장에서 먹는배와 , 신체 배의 차이를 극대화하는 과정과 같다. 먹었다,아프다 라는단어와의 상관관계를 분석하여 배라는 단어가 어떤것에 더 가까운지 확실히하는 과정이라고 생각하면 된다.
  • 위사진에서 4, embedding dimension이 의미하는것은?
    • 자연어처리에서는 단어가 들어오면 단어를 토큰화하고, word embedding을 통해서 벡터화한다.
      • 어떤흐름으로 진행되는지는 아래 그림을 참조
      • integer부분이 토큰화, lookup table에서 한줄 뽑아온것(위그림의 단어별로 존재하는 리스트) 바로 임베딩 벡터를 의미한다.

⇒ 한마디로 이과정은 각각의 단어들을 비교해서 문맥을 파악하고, 벡터표현값을 업데이트하는 과정

 

< 헷갈리는것들 >

여기서 간과하면 안되는점 : Wq의 크기는 d_model x d_model이다. (Tx d_model) x (d_model*d_model) 이렇게 행렬곱셈을 하면 결과값 크기도 input과 동일한 T x d_model이 나옴

 

<추가설명>

  • 위사진에서 4, embedding dimension이 의미하는것은?
    • 자연어처리에서는 단어가 들어오면 단어를 토큰화하고, word embedding을 통해서 벡터화한다.
      • 어떤흐름으로 진행되는지는 아래 그림을 참조하자
      • 아래그림에서 integer부분이 토큰화, lookup table에서 한줄 뽑아온것(위그림의 단어별로 존재하는 리스트) 바로 임베딩 벡터를 의미한다.

 

 

2. Multihead attention

 

참조 (아래 더보기 클릭)

위 그림이 논문에 나온 그림이다.

 

  • h는 사용자가 직접 정해준다. 멀티헤드를 몇개로 지정해줄것인가를 뜻한다.
  • h(멀티헤드 갯수)를 직접 정해주지않으면 디폴트값은 12개이다.
  • 앞에서 self attention으로 구한 블럭을 가로로 나란히 h개 붙인다
  • 그다음, w0 행렬에 곱해서 linear하게 재정렬한다.
  • 한마디로 맨위에서 wo랑 곱하는 과정이 concat
  • concat를 해서 리니어하게 재정렬 된다는것을 의미한다.
  • transformer paper에서 w0는 가로세로 길이가 같음 (d0=dv*h)

 

 

참조 : https://medium.com/analytics-vidhya/understanding-bert-architecture-3f35a264b187

위 링크에서 보면 keras_bert로 multihead attention이 끝나고 파라미터수가 Bert는 인코더수가 12개이기 때문에 encoder-1의 multihead self attnetion의 파라미터수가 2,362,368개가 나오는지 계산해보자

import keras
from keras_bert import get_base_dict, get_model, compile_model, gen_batch_inputs

model = get_model(
    token_num=30000,
    head_num=12,
    transformer_num=12,
    embed_dim=768,
    feed_forward_dim=3072,
    seq_len=500,
    pos_num=512,
    dropout_rate=0.05
)
model.summary()

  • parameter를 구하기위해서는 위에서 wq,wk,wv랑 w0의 수를 모두 더해주면된다.
  • 일반적으로 self-attention에서는 w1q크기가 d_model x d_model이지만 여기서는 multihead attention이기 떄문에 d_model x d_model/h 로 구성되게 된다.
    • 위의 예제에서 dm = 768, h=12로 지정해준 상태이다.
    • 그렇다면 wq의 크기는 768*64 근데 이게 k,v,q 이렇게 3개가 있으니까 3을 곱해주고, 헤드가 12개니까 12도 곱해준다.
    • 그런데 바이어스도 더해줘야한다고함..
    • 그렇다면 wq,wv,wk의 모든 파라미터갯수는 76864312+7683
    • w0은 쉽다. d_model x d_model인데 여기도 바이어스값을 더해줘야한다고
      • 그래서 768*768 + 768
    • 모두다 더해주면 2362368개의 파라미터수가 나온다!

 

 

3. Layer Norm

 

  • 그림에서는 norm이 multihead 다음, 피드 포워드 다음에 진행되지만 최근 LLM모델들은 전부 norm을 먼저 진행한다고 한다 (최근은 순서가 반대라고함)
    • 실제로 아래 BERT모델을 보면 Layer norm을 먼저하고나서 multihead attention을 진행한다.

  • 먼저 딥러닝을 진행할때 activation function에서 input데이터들이 너무 왼쪽이나 너무 오른쪽에 붙으면 문제가 생김
  • 그걸 방지하고자 nomarlization을 진행, 이때 정규화분포의 모양과 위치는 감마와 베타가 결정함.

  • Multihead attention을 적용하기 전에 normalization을 적용
  • 세로 한줄 한줄씩 정규화하여 감마와 베타값도 구함.
  • 이렇게 정규화한 값들을 가지고 멀티헤드 어텐션을 구함
  • 원본과 멀티헤드 어텐션으로 나온값을 더해준다.

 

 

4. Feed Forward

참조 (아래 더보기 클릭)

여기까지 싹하고나면, 아래 그림은 인코더 부분을 정리해서 나타낸 그림.

 

 

이것도 파라미터수가 feed forward후에 왜 4722432개 나오는 이유를 보자

 

'<개념> > Deep learning' 카테고리의 다른 글

What is Agent Force?  (0) 2024.11.03
LLAMA Inference  (0) 2024.05.17
T5 inference in inferentia  (0) 2024.04.08
openai gpt3 inference in inferentia2(neruon)  (0) 2024.03.28
GPT2 Text-generation을 AWS환경의 GPU/CPU/Inf2/Trn1에서..  (1) 2024.01.29

LLAMA 너무 커서 inf2.24large에서 시작하기 (허깅 페이스 토큰도 만들어야함)

AMI : Deep Learning AMI Neuron PyTorch 1.13 (Ubuntu 20.04) 20231003

source /opt/aws_neuron_venv_pytorch/bin/activate
pip3 install transformers-neuronx --extra-index-url=https://pip.repos.neuron.amazonaws.com
pip3 install optimum
pip3 install -U "huggingface_hub[cli]"
huggingface-cli login

 

llama 사용권한요청1 : https://llama.meta.com/llama-downloads/

llama 사용권한요청2 : https://huggingface.co/meta-llama/Llama-2-7b-hf

코드1

from transformers import AutoTokenizer, LlamaForCausalLM
from huggingface_hub import login

login("본인 허깅페이스 토큰~")

model = LlamaForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")

prompt = "Hey, are you conscious? Can you talk to me?"
inputs = tokenizer(prompt, return_tensors="pt")

# Generate
generate_ids = model.generate(inputs.input_ids, max_length=30)
output = tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
print(output)

코드2

import time
import torch
from transformers import AutoTokenizer
from transformers_neuronx import LlamaForSampling
from huggingface_hub import login

login("본인토큰")
  
# load meta-llama/Llama-2-13b to the NeuronCores with 24-way tensor parallelism and run compilation
neuron_model2 = LlamaForSampling.from_pretrained('meta-llama/Llama-2-7b-chat-hf', batch_size=1, tp_degree=12, amp='f16')
neuron_model2.to_neuron() 

# construct a tokenizer and encode prompt text
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-chat-hf")

prompt = ["Hello, I'm a language model,"]
#input_ids = tokenizer.encode(prompt, return_tensors="pt")
encoded_input = tokenizer(prompt, return_tensors='pt')

# run inference with top-k sampling
with torch.inference_mode():
    start = time.time()
    generated_sequences = neuron_model2.sample(encoded_input.input_ids, sequence_length=128, top_k=50)
    elapsed = time.time() - start

generated_sequences = [tokenizer.decode(seq) for seq in generated_sequences]
print(f'generated sequences {generated_sequences} in {elapsed} seconds')

https://awsdocs-neuron.readthedocs-hosted.com/en/latest/src/examples/pytorch/torch-neuronx/t5-inference-tutorial.html

source /opt/aws_neuron_venv_pytorch/bin/activate
pip install transformers-neuronx --extra-index-url=https://pip.repos.neuron.amazonaws.com
pip install --upgrade transformers==4.31.0 optimum-neuron==0.0.8
pip install torch_xla

AMI는

코드는 아래 더보기 누르기~

더보기
import torch
import datetime


from transformers.models.t5.modeling_t5 import T5Stack, T5LayerCrossAttention

class EncoderWrapper(torch.nn.Module):
    '''
        We will trace an instance of the EncoderWrapper.
        This wrapper just converts positional args to kwargs.
    '''

    def __init__(self,
                 encoder,
                 decoder,
                 model_config,
                 batch_size,
                 max_length,
                 device,
                 num_beams,
                 tp_degree=None):

        super().__init__()
        self.encoder = encoder
        self.decoder = decoder
        self.batch_size = batch_size
        self.max_length = max_length
        self.model_config = model_config
        self.device = device
        self.num_beams = num_beams
        self.num_attention_heads_per_partition = model_config.num_heads
        self.tp_degree = tp_degree

    def forward(self, input_ids, attention_mask):
        '''
            This is the core functionality we want to trace.
        '''
        encoder_output =  self.encoder(input_ids=input_ids,
                                       attention_mask=attention_mask,
                                       output_attentions=False,
                                       output_hidden_states=False)

        last_hidden_state = encoder_output["last_hidden_state"]
        encoder_hidden_states = torch.concat([tensor.unsqueeze(0).repeat(self.num_beams, 1, 1) for tensor in last_hidden_state])

        decoder_blocks = self.decoder.block
        present_key_value_states_sa = []
        present_key_value_states_ca = []

        for i, block in enumerate(decoder_blocks):

            # Cross attention has to be initialized with the encoder hidden state
            cross_attention: T5LayerCrossAttention = block.layer[1]
            attention = cross_attention.EncDecAttention

            def shape(states):
                """projection"""
                return states.view(self.batch_size, -1, self.num_attention_heads_per_partition, attention.key_value_proj_dim).transpose(1, 2)

            key_states = shape(attention.k(encoder_hidden_states))
            value_states = shape(attention.v(encoder_hidden_states))

            # cross_attn_kv_state
            present_key_value_states_ca.append(key_states)
            present_key_value_states_ca.append(value_states)

            # Self attention kv states are initialized to zeros. This is done to keep the size of the kv cache tensor constant.
            # The kv cache will be an input to the decoder trace. Any traced function will have a fixed control flow. What this means
            # is that the trace performs the exact same computations on inputs of the same shape in each invocation. So the attention
            # kv cache is padded here to keep a fixed shape.
            present_key_value_states_sa.append(torch.zeros((self.batch_size,                                                     # key states
                                                            self.model_config.num_heads,
                                                            self.max_length-1,
                                                            self.model_config.d_kv), dtype=torch.float32, device=self.device))
            present_key_value_states_sa.append(torch.zeros((self.batch_size,                                                     # value states
                                                            self.model_config.num_heads,
                                                            self.max_length-1,
                                                            self.model_config.d_kv), dtype=torch.float32, device=self.device))

        return present_key_value_states_sa + present_key_value_states_ca


class DecoderWrapper(torch.nn.Module):

    def __init__(self,
                 decoder: T5Stack,
                 lm_head: torch.nn.Linear,
                 model_config,
                 num_beams: int,
                 max_length: int,
                 device: str,
                 tp_degree=None):
        super().__init__()
        self.decoder = decoder
        self.lm_head = lm_head
        self.model_dim=model_config.d_model
        self.device = device
        self.num_beams = num_beams
        self.batch_size = 1
        self.config = model_config

        num_heads=model_config.num_heads
        num_decoder_layers=model_config.num_decoder_layers

        self.num_attention_heads_per_partition = num_heads

        # (num_beams, n_heads, seq_length, dim_per_head)
        if device == "cpu":
            self.past_key_values_sa = [torch.ones((num_beams,num_heads,max_length-1,model_config.d_kv), dtype=torch.float32) for _ in range(num_decoder_layers * 2)]
            self.past_key_values_ca = [torch.ones((num_beams,num_heads,max_length,model_config.d_kv), dtype=torch.float32) for _ in range(num_decoder_layers * 2)]
        elif device == "xla":
            self.past_key_values_sa = torch.nn.ParameterList([torch.nn.Parameter(torch.ones((num_beams,self.num_attention_heads_per_partition,max_length-1,model_config.d_kv), dtype=torch.float32), requires_grad=False) for _ in range(num_decoder_layers * 2)])
            self.past_key_values_ca = torch.nn.ParameterList([torch.nn.Parameter(torch.ones((num_beams,self.num_attention_heads_per_partition,max_length,model_config.d_kv), dtype=torch.float32), requires_grad=False) for _ in range(num_decoder_layers * 2)])

    def update_past(self, past_key_values):
        new_past_sa = []
        new_past_ca = []
        for past_layer in past_key_values:
            new_past_layer = list(past_layer)
            for i in range(len(new_past_layer[:2])):
                new_past_layer[i] = past_layer[i][:, :, 1:]
            new_past_sa += [new_past_layer[:2],]
            new_past_ca += [new_past_layer[2:],]
        return new_past_sa, new_past_ca

    def reorder_cache(self, past_key_values, beam_idx):
        for i in range(len(past_key_values)):
            gather_index = beam_idx.view([beam_idx.shape[0],1,1,1]).expand_as(past_key_values[i])
            past_key_values[i] = torch.gather(past_key_values[i], dim = 0, index=gather_index)
        return past_key_values

    def forward(self,
                input_ids,
                decoder_attention_mask,
                encoder_hidden_states,
                encoder_attention_mask,
                beam_idx,
                beam_scores,
                **kwargs):

        if self.num_beams > 1:
            # We reorder the cache based on the beams selected in each iteration. Required step for beam search.
            past_key_values_sa = self.reorder_cache(self.past_key_values_sa, beam_idx)
            past_key_values_ca = self.reorder_cache(self.past_key_values_ca, beam_idx)
        else:
            # We do not need to reorder for greedy sampling
            past_key_values_sa = self.past_key_values_sa
            past_key_values_ca = self.past_key_values_ca

        # The cache is stored in a flatten form. We order the cache per layer before passing it to the decoder.
        # Each layer has 4 tensors, so we group by 4.
        past_key_values = [[*past_key_values_sa[i*2:i*2+2], *past_key_values_ca[i*2:i*2+2]] for i in range(0, int(len(past_key_values_ca)/2))]

        decoder_output = self.decoder(
            input_ids=input_ids,
            attention_mask=decoder_attention_mask,
            past_key_values=past_key_values,
            encoder_hidden_states=encoder_hidden_states,
            encoder_attention_mask=encoder_attention_mask,
            use_cache=True,
            output_attentions=False,
            output_hidden_states=False)

        last_hidden_state = decoder_output['last_hidden_state']
        past_key_values = decoder_output['past_key_values']

        if self.config.tie_word_embeddings:
            # Rescale output before projecting on vocab
            # See https://github.com/tensorflow/mesh/blob/fa19d69eafc9a482aff0b59ddd96b025c0cb207d/mesh_tensorflow/transformer/transformer.py#L586
            last_hidden_state = last_hidden_state * (self.model_dim**-0.5)

        lm_logits = self.lm_head(last_hidden_state)

        past_key_values_sa, past_key_values_ca = self.update_past(past_key_values)

        # We flatten the cache to a single array. This is required for the input output aliasing to work
        past_key_values_sa = [vec for kv_per_layer in past_key_values_sa for vec in kv_per_layer]
        past_key_values_ca = [vec for kv_per_layer in past_key_values_ca for vec in kv_per_layer]

        if self.device == "cpu":
            self.past_key_values_sa = past_key_values_sa
            self.past_key_values_ca = past_key_values_ca

        # We calculate topk inside the wrapper
        next_token_logits = lm_logits[:, -1, :]

        if self.num_beams > 1:
            # This section of beam search is run outside the decoder in the huggingface t5 implementation.
            # To maximize the computation within the neuron device, we move this within the wrapper
            logit_max, _ = torch.max(next_token_logits, dim=-1, keepdim=True)
            logsumexp = torch.log(torch.exp(next_token_logits - logit_max).sum(dim=-1, keepdim=True))
            next_token_scores = next_token_logits - logit_max - logsumexp
            next_token_scores = next_token_scores + beam_scores[:, None].expand_as(next_token_scores)

            # reshape for beam search
            vocab_size = next_token_scores.shape[-1]
            next_token_scores = next_token_scores.view(self.batch_size, self.num_beams * vocab_size)
            next_token_scores = next_token_scores * 1

            # Sample 2 next tokens for each beam (so we have some spare tokens and match output of beam search)
            next_token_scores, next_tokens = torch.topk(
                next_token_scores, 2 * self.num_beams, dim=1, largest=True, sorted=True
            )

            next_indices = torch.div(next_tokens, vocab_size, rounding_mode="floor")
            next_tokens = next_tokens % vocab_size

            return [next_token_scores, next_tokens, next_indices] + past_key_values_sa + past_key_values_ca
        else:
            # Greedy
            next_tokens = torch.argmax(next_token_logits, dim=-1)
            return [next_tokens] + past_key_values_sa + past_key_values_ca

import torch
import torch_xla.core.xla_model as xm

from transformers import T5Tokenizer, T5ForConditionalGeneration
from transformers.modeling_outputs import BaseModelOutput, Seq2SeqLMOutput
from transformers.models.t5.modeling_t5 import T5Stack, T5LayerCrossAttention
from transformers.generation.utils import ModelOutput
from typing import Any, Dict, List, Optional, Tuple, Union
from transformers.generation.beam_search import BeamScorer, BeamSearchScorer

from optimum.neuron.generation import NeuronGenerationMixin

from transformers.generation.logits_process import (
    LogitsProcessorList,
)
from transformers.generation.stopping_criteria import (
    MaxLengthCriteria,
    MaxTimeCriteria,
    StoppingCriteriaList,
    validate_stopping_criteria,
)

from transformers.generation.utils import (
    BeamSearchOutput,
    GreedySearchOutput,
)

class T5Wrapper(T5ForConditionalGeneration, NeuronGenerationMixin):

    def _prepare_encoder_decoder_kwargs_for_generation(
        self,
        inputs_tensor: torch.Tensor,
        model_kwargs,
        model_input_name: Optional[str] = None
    ) -> Dict[str, Any]:
        encoder = self.get_encoder()
        model_kwargs["encoder_outputs"]: ModelOutput = encoder(inputs_tensor, model_kwargs["attention_mask"])
        return model_kwargs

    # Override to cut the input_ids to just last token
    def prepare_inputs_for_generation(
        self,
        input_ids,
        past_key_values=None,
        attention_mask=None,
        head_mask=None,
        decoder_head_mask=None,
        decoder_attention_mask=None,
        cross_attn_head_mask=None,
        use_cache=None,
        encoder_outputs=None,
        **kwargs,
    ):
        # cut decoder_input_ids as past is cached
        input_ids = input_ids[:, -1:]

        return {
            "decoder_input_ids": input_ids,
            "past_key_values": past_key_values,
            "encoder_outputs": encoder_outputs,
            "attention_mask": attention_mask,
            "head_mask": head_mask,
            "decoder_head_mask": decoder_head_mask,
            "decoder_attention_mask": decoder_attention_mask,
            "cross_attn_head_mask": cross_attn_head_mask,
            "use_cache": use_cache,
        }

    '''
        We update the cache in the decoder trace, so lets override the _update_model_kwargs_for_xla_generation in NeuronGenerationMixin
    '''
    def _update_model_kwargs_for_xla_generation(
        self,
        model_kwargs: Dict[str, Any],
        batch_size: int,
        is_encoder_decoder: bool = False,
        standardize_cache_format: bool = False,
        max_length: Optional[int] = None,
        seq_length: Optional[int] = None,
        use_cache: bool = True,
    ) -> Dict[str, Any]:

        def _update_attention(model_kwargs, is_encoder_decoder):
            """Updates the appropriate attention mask -- encoder-decoder models use `decoder_attention_mask`"""

            attention_mask_name = "decoder_attention_mask" if is_encoder_decoder else "attention_mask"
            attention_mask = model_kwargs.pop(attention_mask_name)
            attention_mask_update_slice = torch.ones(
                (batch_size, 1), dtype=attention_mask.dtype, device=attention_mask.device
            )
            attention_mask = torch.cat([attention_mask[:, 1:], attention_mask_update_slice], dim=-1)
            mask = {attention_mask_name: attention_mask}
            return mask

        mask = _update_attention(model_kwargs, is_encoder_decoder)
        # sets the updated variables (mask and past_key_values)
        model_kwargs.update(mask)

        # Set a mock cache tensor
        model_kwargs["past_key_values"] = torch.tensor([])

        return model_kwargs

    def _reorder_cache(self, past_key_values, beam_idx):
        '''
            This is needed for beam search and not greedy sampling
            We reorder the cache within the trace so we can skip it in modelling_t5.py. So we override the _reorder_cache
        '''
        self.beam_idx = beam_idx
        return past_key_values

    def generate(self,
                tokenizer: T5Tokenizer,
                prompt: str,
                max_length: int,
                num_beams: int,
                num_return_sequences: int,
                device: str):

        batch_encoding = tokenizer(prompt, max_length=max_length, truncation=True, padding='max_length',
                                return_tensors="pt")

        past_key_values = self.encoder(batch_encoding['input_ids'],batch_encoding['attention_mask'])

        decoder_attention_mask = torch.cat([torch.zeros((1, max_length-1), dtype=torch.int32),
                                            torch.ones((1, 1), dtype=torch.int32)], axis=1)

        # copy the new cache state to the decoder
        if device == "xla":
            for state, tensor in zip(self.decoder.parameters(), past_key_values):
                state.copy_(tensor)
        else:
            # First half of the cache is self attention and the rest is cross attention
            self.decoder.past_key_values_sa = past_key_values[:len(past_key_values)//2]
            self.decoder.past_key_values_ca = past_key_values[len(past_key_values)//2:]

        output = super().generate(**batch_encoding,
                                max_length=max_length,
                                num_beams=num_beams,
                                num_return_sequences=num_return_sequences,
                                do_sample=False,
                                use_cache=True,
                                decoder_attention_mask=decoder_attention_mask,
                                encoder_outputs={"last_hidden_state": torch.ones((1,128,1))}) # Pass fake encoder_outputs so the transfomers code will not invoke the encoder
        return output

    def forward(
        self,
        attention_mask: Optional[torch.FloatTensor] = None,
        decoder_input_ids: Optional[torch.LongTensor] = None,
        decoder_attention_mask: Optional[torch.BoolTensor] = None,
        encoder_outputs: Optional[Tuple[Tuple[torch.Tensor]]] = None,
        beam_scores = None,
        **kwargs
    ) -> Union[Tuple[torch.FloatTensor], Seq2SeqLMOutput]:

        hidden_states = encoder_outputs["last_hidden_state"]

        if not hasattr(self, 'beam_idx'):
            # Infering the number of beams from the attention mask
            num_beams = attention_mask.shape[0]
            self.beam_idx = torch.arange(0, num_beams, dtype=torch.int64)

        decoder_outputs = self.decoder(
            decoder_input_ids,
            decoder_attention_mask,
            hidden_states,
            attention_mask,
            self.beam_idx,
            beam_scores
        )

        # lm_logits = decoder_outputs[0]
        next_token_scores = decoder_outputs[0]
        next_tokens = decoder_outputs[1]
        next_indices = decoder_outputs[2]

        return next_token_scores, next_tokens, next_indices

    def beam_search(
        self,
        input_ids: torch.LongTensor,
        beam_scorer: BeamScorer,
        logits_processor: Optional[LogitsProcessorList] = None,
        stopping_criteria: Optional[StoppingCriteriaList] = None,
        max_length: Optional[int] = None,
        pad_token_id: Optional[int] = None,
        eos_token_id: Optional[Union[int, List[int]]] = None,
        output_attentions: Optional[bool] = None,
        output_hidden_states: Optional[bool] = None,
        output_scores: Optional[bool] = None,
        return_dict_in_generate: Optional[bool] = None,
        synced_gpus: Optional[bool] = False,
        seq_length: Optional[int] = None,
        **model_kwargs,
    ) -> Union[BeamSearchOutput, torch.LongTensor]:

        logits_processor = logits_processor if logits_processor is not None else LogitsProcessorList()
        stopping_criteria = stopping_criteria if stopping_criteria is not None else StoppingCriteriaList()
        pad_token_id = pad_token_id if pad_token_id is not None else self.generation_config.pad_token_id
        eos_token_id = eos_token_id if eos_token_id is not None else self.generation_config.eos_token_id
        if isinstance(eos_token_id, int):
            eos_token_id = [eos_token_id]
        output_scores = output_scores if output_scores is not None else self.generation_config.output_scores
        output_attentions = (
            output_attentions if output_attentions is not None else self.generation_config.output_attentions
        )
        output_hidden_states = (
            output_hidden_states if output_hidden_states is not None else self.generation_config.output_hidden_states
        )

        batch_size = len(beam_scorer._beam_hyps)
        num_beams = beam_scorer.num_beams

        batch_beam_size, cur_len = input_ids.shape

        # Overwrite cur_len
        cur_len = seq_length

        if num_beams * batch_size != batch_beam_size:
            raise ValueError(
                f"Batch dimension of `input_ids` should be {num_beams * batch_size}, but is {batch_beam_size}."
            )

        # init attention / hidden states / scores tuples
        scores = () if (return_dict_in_generate and output_scores) else None
        beam_indices = (
            tuple(() for _ in range(batch_beam_size)) if (return_dict_in_generate and output_scores) else None
        )

        # initialise score of first beam with 0 and the rest with -1e9. This makes sure that only tokens
        # of the first beam are considered to avoid sampling the exact same tokens across all beams.
        # beam_scores = torch.zeros((batch_size, num_beams), dtype=torch.float, device=input_ids.device)
        beam_scores_device = "cpu"
        beam_scores = torch.zeros((batch_size, num_beams), dtype=torch.float, device=beam_scores_device)
        beam_scores[:, 1:] = -1e9
        beam_scores = beam_scores.view((batch_size * num_beams,))

        while True:
            # prepare model inputs
            # From max_length-sized input_ids, select first
            # cur_len - 1 values.
            update_indices = torch.stack(
                [torch.arange(input_ids.size(0)), torch.tensor(cur_len - 1).repeat(input_ids.size(0))], dim=-1
            )
            input_ids_ = input_ids[update_indices[:, 0], update_indices[:, 1], None]
            model_inputs = self.prepare_inputs_for_generation(input_ids_, **model_kwargs)

            next_token_scores, next_tokens, next_indices = self(
                **model_inputs,
                return_dict=True,
                output_attentions=output_attentions,
                output_hidden_states=output_hidden_states,
                beam_scores=beam_scores
            )

            # stateless
            beam_outputs = beam_scorer.process(
                input_ids.to("cpu")[:, :cur_len],
                next_token_scores.to("cpu"),
                next_tokens.to("cpu"),
                next_indices.to("cpu"),
                pad_token_id=pad_token_id,
                eos_token_id=eos_token_id,
                beam_indices=beam_indices,
            )

            beam_scores = beam_outputs["next_beam_scores"]
            beam_next_tokens = beam_outputs["next_beam_tokens"]
            beam_idx = beam_outputs["next_beam_indices"]

            update_indices = torch.stack(
                [torch.arange(batch_beam_size), torch.tensor(cur_len - 1).repeat(batch_beam_size)], dim=-1
            )
            update_indices_2 = torch.stack(
                [torch.arange(batch_beam_size), torch.tensor(cur_len).repeat(batch_beam_size)], dim=-1
            )
            # First select beam_indices
            device = input_ids.device
            beam_idx_device = beam_idx.to(device=input_ids.device)
            input_ids[:, :] = input_ids[beam_idx_device.long(), :]

            # Then append new tokens
            input_ids[update_indices_2[:, 0], update_indices_2[:, 1], None] = beam_next_tokens.unsqueeze(-1).to(device).to(torch.long)
            input_ids = input_ids * 1  # Hack to materialize tensor

            # update generated ids, model inputs, and length for next step
            model_kwargs = self._update_model_kwargs_for_xla_generation(
                model_kwargs,
                batch_size=batch_beam_size,
                is_encoder_decoder=self.config.is_encoder_decoder,
                max_length=stopping_criteria.max_length,
                seq_length=cur_len,
                use_cache=model_kwargs["use_cache"],
            )
            if model_kwargs["past_key_values"] is not None:
                model_kwargs["past_key_values"] = self._reorder_cache(model_kwargs["past_key_values"], beam_idx.to(torch.int64))

            if return_dict_in_generate and output_scores:
                beam_indices = tuple((beam_indices[beam_idx[i]] + (beam_idx[i],) for i in range(len(beam_indices))))

            # increase cur_len
            cur_len = cur_len + 1

            # stop when each sentence is finished, or if we exceed the maximum length
            stop_criterion_1 = beam_scorer.is_done
            if isinstance(stopping_criteria, list):
                if len(stopping_criteria) == 1:
                    stopping_criteria = stopping_criteria[0]

            # Cases that can be handled in XLA without requiring
            # non-padded input_ids
            if isinstance(stopping_criteria, MaxLengthCriteria):
                stop_criterion_2 = cur_len >= stopping_criteria.max_length
            elif isinstance(stopping_criteria, MaxTimeCriteria):
                stop_criterion_2 = stopping_criteria(input_ids, scores)
            else:
                # Other cases will be handled on CPU
                batch_size, _ = input_ids.shape
                input_ids_cpu = input_ids.to("cpu")
                mask = torch.cat(
                    [torch.ones(batch_size, cur_len), torch.zeros(batch_size, input_ids.shape[1] - cur_len)], dim=1
                ).bool()
                input_ids_cpu = torch.masked_select(input_ids_cpu, mask).reshape((batch_size, cur_len))
                scores_cpu = scores.to("cpu") if torch.is_tensor(scores) else scores
                stop_criterion_2 = stopping_criteria(input_ids_cpu, scores_cpu)

            if stop_criterion_1 or stop_criterion_2:
                if not synced_gpus:
                    break
                else:
                    this_peer_finished = True

        sequence_outputs = beam_scorer.finalize(
            input_ids.to("cpu"),
            beam_scores.to("cpu"),
            next_tokens.to("cpu"),
            next_indices.to("cpu"),
            pad_token_id=pad_token_id,
            eos_token_id=eos_token_id,
            max_length=stopping_criteria.max_length,
            beam_indices=beam_indices,
        )

        for k, v in sequence_outputs.items():
            if type(v) == torch.Tensor:
                sequence_outputs[k] = sequence_outputs[k].to(input_ids.device)

        return sequence_outputs["sequences"]


    def greedy_search(
        self,
        input_ids: torch.LongTensor,
        logits_processor: Optional[LogitsProcessorList] = None,
        stopping_criteria: Optional[StoppingCriteriaList] = None,
        max_length: Optional[int] = None,
        pad_token_id: Optional[int] = None,
        eos_token_id: Optional[Union[int, List[int]]] = None,
        output_attentions: Optional[bool] = None,
        output_hidden_states: Optional[bool] = None,
        output_scores: Optional[bool] = None,
        return_dict_in_generate: Optional[bool] = None,
        seq_length: Optional[int] = int,
        streamer: Optional["BaseStreamer"] = None,
        **model_kwargs,
    ) -> Union[GreedySearchOutput, torch.LongTensor]:
        """
            Overriding greedy sampling to use next tokens returned from neuron device instead of logits.
        """
        # init values
        logits_processor = logits_processor if logits_processor is not None else LogitsProcessorList()
        use_cache = model_kwargs["use_cache"] if "use_cache" in model_kwargs else False
        stopping_criteria = stopping_criteria if stopping_criteria is not None else StoppingCriteriaList()
        pad_token_id = pad_token_id if pad_token_id is not None else self.generation_config.pad_token_id
        eos_token_id = eos_token_id if eos_token_id is not None else self.generation_config.eos_token_id
        if isinstance(eos_token_id, int):
            eos_token_id = [eos_token_id]
        eos_token_id_tensor = torch.tensor(eos_token_id).to(input_ids.device) if eos_token_id is not None else None
        output_scores = output_scores if output_scores is not None else self.generation_config.output_scores
        output_attentions = (
            output_attentions if output_attentions is not None else self.generation_config.output_attentions
        )
        output_hidden_states = (
            output_hidden_states if output_hidden_states is not None else self.generation_config.output_hidden_states
        )

        # init attention / hidden states / scores tuples
        scores = () if (return_dict_in_generate and output_scores) else None
        decoder_attentions = () if (return_dict_in_generate and output_attentions) else None
        cross_attentions = () if (return_dict_in_generate and output_attentions) else None
        decoder_hidden_states = () if (return_dict_in_generate and output_hidden_states) else None


        # keep track of which sequences are already finished
        unfinished_sequences = torch.ones(input_ids.shape[0], dtype=torch.long, device=input_ids.device)

        this_peer_finished = False  # used by synced_gpus only
        while True:

            # prepare model inputs
            # From max_length-sized input_ids, select first
            # seq_length - 1 values.

            if model_kwargs.get("past_key_values") is None:
                input_ids_ = input_ids[:, :seq_length]
            else:
                update_indices = torch.stack(
                    [torch.arange(input_ids.size(0)), torch.tensor(seq_length - 1).repeat(input_ids.size(0))],
                    dim=-1,
                )
                input_ids_ = input_ids[update_indices[:, 0], update_indices[:, 1], None]

            model_inputs = self.prepare_inputs_for_generation(input_ids_, **model_kwargs)

            # forward pass to get next token
            output = self(
               **model_inputs,
                return_dict=True,
                output_attentions=output_attentions,
                output_hidden_states=output_hidden_states,
            )
            next_tokens = output[0]

            # finished sentences should have their next token be a padding token
            if eos_token_id is not None:
                if pad_token_id is None:
                    raise ValueError("If `eos_token_id` is defined, make sure that `pad_token_id` is defined.")
                next_tokens = next_tokens * unfinished_sequences + pad_token_id * (1 - unfinished_sequences)

            # update generated ids, model inputs, and length for next step

            batch_size, _ = input_ids.shape
            update_indices = torch.stack(
                [torch.arange(batch_size), torch.tensor(seq_length).repeat(batch_size)], dim=-1
            )
            input_ids[update_indices[:, 0], update_indices[:, 1]] = next_tokens[:]
            model_kwargs = self._update_model_kwargs_for_xla_generation(
                model_kwargs,
                batch_size=batch_size,
                is_encoder_decoder=self.config.is_encoder_decoder,
                max_length=stopping_criteria.max_length,
                seq_length=seq_length,
                use_cache=use_cache,
            )

            seq_length += 1

            # if eos_token was found in one sentence, set sentence to finished
            if eos_token_id_tensor is not None:
                unfinished_sequences = unfinished_sequences.mul(
                    next_tokens.tile(eos_token_id_tensor.shape[0], 1).ne(eos_token_id_tensor.unsqueeze(1)).prod(dim=0)
                )

            # stop when each sentence is finished, or if we exceed the maximum length
            stop_criterion_1 = unfinished_sequences.max() == 0

            if isinstance(stopping_criteria, list):
                if len(stopping_criteria) == 1:
                    stopping_criteria = stopping_criteria[0]

            # Cases that can be handled in XLA without requiring
            # non-padded input_ids
            if isinstance(stopping_criteria, MaxLengthCriteria):
                stop_criterion_2 = seq_length >= stopping_criteria.max_length
            elif isinstance(stopping_criteria, MaxTimeCriteria):
                stop_criterion_2 = stopping_criteria(input_ids, scores)
            else:
                # Other cases will be handled on CPU
                batch_size, _ = input_ids.shape
                mask = torch.cat(
                    [torch.ones(batch_size, seq_length), torch.zeros(batch_size, input_ids.shape[1] - seq_length)],
                    dim=1,
                ).bool()
                input_ids_cpu = torch.masked_select(input_ids, mask).reshape((batch_size, seq_length)).to("cpu")
                scores_cpu = scores.to("cpu") if torch.is_tensor(scores) else scores
                stop_criterion_2 = stopping_criteria(input_ids_cpu, scores_cpu)

            if stop_criterion_1 or stop_criterion_2:
                this_peer_finished = True

            if this_peer_finished:
                break

        if streamer is not None:
            streamer.end()

        return input_ids


# Let's set some run parameters

model_name = "t5-large"
num_beams = 1
num_return_sequences = 1
max_length = 128

from transformers import T5Tokenizer


prompt="translate English to German: Lets eat good food."

tokenizer = T5Tokenizer.from_pretrained(model_name, model_max_length=max_length)
model = T5Wrapper.from_pretrained(model_name)

model.encoder = EncoderWrapper(model.encoder, model.decoder, model.config, num_beams, max_length, "cpu", num_beams)
setattr(model.encoder, 'main_input_name', 'input_ids')  # Attribute required by beam search

model.decoder = DecoderWrapper(decoder=model.decoder,
                                lm_head=model.lm_head,
                                model_config=model.config,
                                num_beams=num_beams,
                                max_length=max_length,
                                device="cpu")
start = datetime.datetime.now()
output = model.generate(tokenizer=tokenizer,
                        prompt=prompt,
                        max_length=max_length,
                        num_beams=num_beams,
                        num_return_sequences=num_return_sequences,
                        device="cpu")
end = datetime.datetime.now()
total = end - start
print("Execution time: ", total)

results = [tokenizer.decode(t, skip_special_tokens=True) for t in output]

print('Results:')
for i, summary in enumerate(results):
    print(i + 1, summary)

 

import openai

openai.api_key = 'mykey'

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "Hello, I'm a language model,"}
    ]
)
print(response['choices'][0]['message']['content'])

 

< setting>

AMI : Deep Learning AMI Neuron PyTorch 1.13 (Ubuntu 20.04) 20240102

인스턴스 : Inf2.xlarge

source /opt/aws_neuron_venv_pytorch/bin/activate

pip install transformers-neuronx --extra-index-url=https://pip.repos.neuron.amazonaws.com

python3 sample.py

 

 

**코드 참조 : https://platform.openai.com/docs/guides/rate-limits/error-mitigation?context=tier-free 

**코드 참조 2 : 챗지피티4

** openai에서 사용가능한 모델 : https://platform.openai.com/docs/models/overview

첨에 RateLimitError 에러가 나서 limit 확인

https://platform.openai.com/docs/guides/rate-limits/usage-tiers?context=tier-free

 

RateLimitError 해결해볼라고 14000원 결제도 함..

1. GPU / CPU

 

GPU AMI : 

 

CPU AMI : 그냥 ubuntu 20.0 서버

 

참조 : https://github.com/huggingface/transformers/tree/main/examples/pytorch/text-generation

sudo apt-get update
pip3 install accelerate
pip3 install transformers
pip3 install torch
git clone https://github.com/huggingface/transformers.git

cd transformers/examples/pytorch/text-generation

python3 run_generation_inf2.py --model_type gpt2 --model_name_or_path gpt2 --num_return_sequences 1 --prompt="“Hello, I’m a language model,”:" --temperature 0.7

 **  --model_name_or_path gpt2 이부분을 gpt2, gpt2-medium, gpt2-large, gpt2-xl, openai-gpt 로 바꿔줄 수 있음

 

2. Inf2.xlarge / Trn1.2xlarge

 

AMI : Neruon + Pytorch + ubuntu 20.0 조합 아무거나

( Deep Learning AMI Neuron PyTorch 1.13 (Ubuntu 20.04) 20240102 )

참조 : https://awsdocs-neuron.readthedocs-hosted.com/en/latest/libraries/transformers-neuronx/transformers-neuronx-developer-guide.html

source /opt/aws_neuron_venv_pytorch/bin/activate
pip install transformers-neuronx --extra-index-url=https://pip.repos.neuron.amazonaws.com
from transformers_neuronx.gpt2.model import GPT2ForSampling
from transformers_neuronx.generation_utils import HuggingFaceGenerationModelAdapter
from transformers_neuronx.module import save_pretrained_split
from transformers import AutoModelForCausalLM, AutoTokenizer
import datetime

# Load and save the CPU model
model_cpu = AutoModelForCausalLM.from_pretrained('gpt2-xl')
save_pretrained_split(model_cpu, 'gpt2-split')

# Create and compile the Neuron model
model_neuron = GPT2ForSampling.from_pretrained('gpt2-split', batch_size=1, tp_degree=2, n_positions=256, amp='f32', unroll=None)
model_neuron.to_neuron()

# Use the `HuggingFaceGenerationModelAdapter` to access the generate API
model = HuggingFaceGenerationModelAdapter(model_cpu.config, model_neuron)

# Get a tokenizer and exaple input
tokenizer = AutoTokenizer.from_pretrained('gpt2-xl')
tokenizer.pad_token_id = tokenizer.eos_token_id
tokenizer.padding_side = 'left'
text = "Hello, I'm a language model,"
encoded_input = tokenizer(text, return_tensors='pt', padding=True)

# Run inference using temperature
model.reset_generation()
start = datetime.datetime.now()
sample_output = model.generate(
    input_ids=encoded_input.input_ids,
    attention_mask=encoded_input.attention_mask,
    do_sample=True,
    max_length=20,
    temperature=0.7,
)
end = datetime.datetime.now()
total = end - start
print("Execution time: ", total)
print([tokenizer.decode(tok) for tok in sample_output])

위 코드 포함하는 sample.py 생성

** 저 코드에서 gpt2-xl 이부분도 gpt2, gpt2-medium, gpt2-large, gpt2-xl 로 바꿔줄수 있음

Python3 sample.py

 

 

첫번째시도(실패)

- hugging face에서 제공하는 pytorch 코드로 돌리면 손을좀 봐야한다. 이유는 해당코드가 gpu/cpu 전용으로 만들어졌기 때문. 

( https://github.com/huggingface/transformers/blob/main/examples/pytorch/text-generation/run_generation.py )

- torch.jit.trace와 torch_neuron.trace는 모두 PyTorch 모델을 최적화하여 pytorch 모델을 TorchScript로 바꿔주는데 사용함. 그런데 전자는 cpu/gpu 용도이고 후자가 inferentia용으로 Nueron 호환 형식으로 변환. 그래서 후자로 변환해줘야함

- 변환해줘도 뉴런코어의 사용률이 0%

 

두번째시도(성공)

- hugging face 를 베이스로한 다른 추론코드를 찾음. 뉴런코어를 잘 사용함. ( https://awsdocs-neuron.readthedocs-hosted.com/en/latest/libraries/transformers-neuronx/transformers-neuronx-developer-guide.html )

- 사용한 aws ami : AMI : Deep Learning AMI Neuron PyTorch 1.13 (Ubuntu 20.04) 20240102

- 아래 실행해주면됨.

# 참조 : https://github.com/aws-neuron/transformers-neuronx
pip install transformers-neuronx --extra-index-url=https://pip.repos.neuron.amazonaws.com
source /opt/aws_neuron_venv_pytorch/bin/activate
python3 sample.py

- 모니터링 참조는 https://awsdocs-neuron.readthedocs-hosted.com/en/latest/tools/neuron-sys-tools/neuron-monitor-user-guide.html

neuron-monitor -c monitor.conf >> output.json

 

stackingregressor 은 이미 있는 모델들 여러개를 합쳐서 사용하는 메타모델

 

sequential로 만든 모델을 그대로 넣어주면 에러남.

 

1. 아래처럼 KerasRegressor 로 감싸주고 집어넣어줘야함.

2. 맨위에 import KerasRegressor 설치&추가해주면됨.

 

from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.ensemble import StackingRegressor

from keras.wrappers.scikit_learn import KerasRegressor
dnn_estimator = KerasRegressor(build_fn=build_dnn_model(epochs=300, batch_size=16, verbose=1))
estimators = [('br', linear_model.BayesianRidge()),('dnn',dnn_estimator)]
reg = StackingRegressor(estimators=estimators,final_estimator=RandomForestRegressor(n_estimators=10,random_state=42))
reg.fit(train_x, train_y)
reg_pred = reg.predict(test_x).reshape(-1, 1)

 

데이터는 kaggle 주택데이터 사용했고 데이터 다운은 아래 더보기 클릭 

 

X      = train_data[features]
y      = np.log1p(train_data["SalePrice"]) # log1p !!!!!!!!!!!
X_test = test_data[features]
y_true = solution["SalePrice"]
import pandas as pd
import numpy  as np
from pytorch_tabnet.tab_model import TabNetRegressor
from sklearn.model_selection import KFold

pd.set_option('display.max_columns', None) # dataframe 잘림없이 출력
pd.set_option('display.max_rows', None)
pd.set_option('display.max_seq_items', None) # 리스트 잘림없이 출력
pd.options.display.float_format = '{:.5f}'.format  # e, 지수없이 출력
pd.set_option('display.max_colwidth', -1) #pd로 볼때 ...없이 출력
import warnings # warning 무시
warnings.filterwarnings('ignore')
pd.set_option('mode.chained_assignment',  None) # SettingWithCopyWarning 경고끄기
train_data = pd.read_csv('./train.csv')
test_data  = pd.read_csv('./test.csv')
sample     = pd.read_csv('./sample_submission.csv')
solution   = pd.read_csv('./solution.csv')

print(len(train_data))
print(len(test_data))
print(len(sample))
print(len(solution))
features = ['LotArea', 'OverallQual', 'OverallCond', 'YearBuilt', 
            'YearRemodAdd', 'BsmtFinSF1', 'BsmtFinSF2', 'TotalBsmtSF', 
            '1stFlrSF', 'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 
            'BsmtHalfBath', 'HalfBath', 'BedroomAbvGr',  'Fireplaces', 
            'GarageCars', 'GarageArea', 'WoodDeckSF', 'OpenPorchSF', 
            'EnclosedPorch',  'PoolArea', 'YrSold']
X      =      X.apply(lambda x: x.fillna(x.mean()),axis=0)
X_test = X_test.apply(lambda x: x.fillna(x.mean()),axis=0)

X      = X.to_numpy()
y      = y.to_numpy().reshape(-1, 1)
X_test = X_test.to_numpy()

# 결측지 해결
X = np.nan_to_num(X) 
X_test = np.nan_to_num(X_test) 
y = np.nan_to_num(y) 
y_true = np.nan_to_num(y_true)
kf = KFold(n_splits=5, random_state=42, shuffle=True) # 5개로 나누기
predictions_array = []
predictions_array2 = []
CV_score_array    = []
for train_index, test_index in kf.split(X): # train_index는 kfold1회에서 train조합, test_index는 테스트조합
    X_train, X_valid = X[train_index], X[test_index]  # train,valid 조합을 나나눠줌
    y_train, y_valid = y[train_index], y[test_index]  # y도 마찬가지
    regressor = TabNetRegressor(verbose=0,seed=42) # 모델정의
    regressor.fit(X_train=X_train, y_train=y_train, # fit + eval_set 추가
              eval_set=[(X_valid, y_valid)],
              patience=300, max_epochs=2000, #patience=성능이좋지않은 epoch 300번이상 반복되면 그마해라
              eval_metric=['rmse'])
    CV_score_array.append(regressor.best_cost) # 5회반복중에 가장좋은점수 저장저장
    predictions_array.append(np.expm1(regressor.predict(X_test)))
predictions = np.mean(predictions_array,axis=0)
print("The CV score is %.5f" % np.mean(CV_score_array,axis=0) ) # cv score 평균값
# from sklearn.metrics import mean_squared_log_error
# RMSLE = np.sqrt( mean_squared_log_error(y_true, predictions) )
# print("The LB score is %.5f" % RMSLE )

def mape(y_test, pred):
    y_test, pred = np.array(y_test), np.array(pred)
    mape = np.mean(np.abs((y_test - pred) / y_test))
    return mape

print(mape(y_true, predictions)*100)

 

 

여기서 y값에 log1p해주고 마지막에 expm1 해주는이유가 궁금했는데

 

 

Q. log말고 log1p해주는 이유?

로그그래프는 아래 그림처럼 0에 가까운 매우 작은수의 경우 무한 음수로 바뀜. 그래서 데이터보면 -Inf상태로 바뀌는걸 볼수가 있음. 그래서 이걸 방지하기 위해 1을 더해주어 방지하는것임.

Q. 굳이 log 씌워서 진행하는 이유?

데이터가 어떤 구간에 엄청 몰려있는 경우가 있음. 이럴때 log를 씌워주면 정규분포 비슷한 형태로 만들어줄수가 있음. 데이터 불균형을 풀어주기위한 방법

 

 

 

 

참조 

 

자꾸 에러날때 직빵인 방법

pip3 show tensorflow

이걸로 tensorflow 위치를 를 복사해준다. 

 

결과로 나온  /usr/local/lib/python3.6/dist-packages 파일에 있는  tensorboard 파일로 이동해준다. 

그리고 main.py 를 실행시키고 logdir 뒤에는 로그파일이 있는 주소를 가르키면 된다.

(리눅스 : pwd 로 경로위치 복사) 

cd /usr/local/lib/python3.6/dist-packages/tensorboard
python3.6 main.py --logdir="/root/data_generation/logs"

 

 

케라스 sequential 로 만든 모델 저장하는법 & 불러오는법

코드 참조 : https://tykimos.github.io/2017/06/10/Model_Save_Load/

참조 :https://mylifemystudy.tistory.com/69

https://ssongnote.tistory.com/12

 

  • 케라스에서 모델 구성하는법
# 0. 사용할 패키지 불러오기
from keras.utils import np_utils
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Activation
import numpy as np
from numpy import argmax

# 1. 데이터셋 생성하기

# 훈련셋과 시험셋 불러오기
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 데이터셋 전처리
x_train = x_train.reshape(60000, 784).astype('float32') / 255.0
x_test = x_test.reshape(10000, 784).astype('float32') / 255.0

# 원핫인코딩 (one-hot encoding) 처리
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)

# 훈련셋과 검증셋 분리
x_val = x_train[:42000] # 훈련셋의 30%를 검증셋으로 사용
x_train = x_train[42000:]
y_val = y_train[:42000] # 훈련셋의 30%를 검증셋으로 사용
y_train = y_train[42000:]

# 2. 모델 구성하기
model = Sequential()
model.add(Dense(units=64, input_dim=28*28, activation='relu'))
model.add(Dense(units=10, activation='softmax'))

# 3. 모델 학습과정 설정하기
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])

# 4. 모델 학습시키기
model.fit(x_train, y_train, epochs=5, batch_size=32, validation_data=(x_val, y_val))

# 5. 모델 평가하기
loss_and_metrics = model.evaluate(x_test, y_test, batch_size=32)
print('')
print('loss_and_metrics : ' + str(loss_and_metrics))

# 6. 모델 사용하기
xhat_idx = np.random.choice(x_test.shape[0], 5)
xhat = x_test[xhat_idx]
yhat = model.predict_classes(xhat)

for i in range(5):
    print('True : ' + str(argmax(y_test[xhat_idx[i]])) + ', Predict : ' + str(yhat[i]))
위 코드 관련된 내용

** reshape 관련참조 https://supermemi.tistory.com/12

** utils.to_categorical

** model.compile → optimizer,loss,metrics 지정해줌.

** loss 함수 참조 https://hororolol.tistory.com/375

** train (val , train ) / test 이렇게 나눠짐

** predict vs predict_class

  • predict 의 경우

[[0.22520512],[0.9520419 ],[0.9672848 ],[0.02690617]]

  • predict_classes 의 경우

[[0],[1],[1],[0]]

** argmax

 

Q. 저장한 모델은 어떻게 다시 불러오고 불러온 모델을 어떤식으로 활용하는지
  • 모델을 저장한다. 무엇을 저장하는건지

모델은 1. 모델 아키텍쳐 (모델이 어떤레이어로 쌓여있는지= 즉 모델구성) 2. 모델가중치(처음에는 임의의값으로 초기화되어있지만, 훈련셋으로 학습하면서 갱신됨) 로 이루어짐. 모델을 저장한다는 의미는 이 두개를 저장한다는 말.

  • 위코드를 실행하고나면 ~~.h5 파일이 생김. 여기에 들어있는 정보들은

(1) 모델구성정보 (2) 가중치 (3) 손실함수등등 학습설정(model.compile해준거) (4) 재학습을 할수있도록 마지막 학습상태 들로 구성되어있다.

→ 만약에 (1) 모델구성정보와 (2) 가중치를 따로 각각 저장하고 불러오는 케이스일경우, 모델을 불러온다음, model.compile을 설정해주어야한다.

 

 

Python sklearn 로 만든 모델 저장하는법

참조: https://cocook.tistory.com/46

https://www.python2.net/questions-889925.htm

Tensorflow 만든 모델 저장,불러오는법

TENSORFLOW

model.save()를 호출하면 다음과 같은 파일들이 저장된다.

  • model's architecture/config
  • model's weight values
  • model's compilation information (if compile() was called)
  • optimizer and its state

model.save('my_custom_model')시 저장되는 디렉토리는 다음과 같다.

my_custom_model 
└ assets (dir) 
└ variables (dir) 
└ saved_model.pb (file)

불러올때는 아래처럼 불러오면 된다

model_dnn = load_model('my_custom_model')

 

 

람다에서 불러올때 h5로 불러오면 에러가 나고, pb 형태로만 인식이 되나보다. 변환해주면 됨

**KERAS (.H5)→ Tensorflow (.pb) 형식

https://coredump064.tistory.com/80 참조 (h5→pb)

 

본인이 변환해서 저장한 saved_dnn_model 형태는 파일형태로 다음과 같았다.

saved_dnn_model
ㄴkeras_metadata.pb
ㄴsaved_model.pb
ㄴvariables
ㄴassets

 

 

Uploaded by Notion2Tistory v1.1.0

 

1. 일단 opencv로 동영상을 잘라준다

2. yolo 적용해서 object detection 감지 ( 아래 사이트 참조)

coco.names
0.00MB
yolov3.cfg
0.01MB
yolo_object_detection.zip
2.76MB

* yoloc3.weighs 는 아래에서 다운로드받아서 쓰기 

 

YOLO object detection using Opencv with Python - Pysource

We’re going to learn in this tutorial YOLO object detection. Yolo is a deep learning algorythm which came out on may 2016...

pysource.com

 

mp4_cctv_list=[]
for i in file_list:
    # 현재 디렉토리에 있는 모든 파일 리스트를 가져온다
    
    path = "./task1/"+str(i)
    file_listttt = os.listdir(path)
    mp4_cctv = [file for file in file_listttt if file.endswith(".mp4")]
    mp4_cctv_list.append(mp4_cctv)


for j in range(1,len(file_list)):
    mp4_cctv = "./task1/"+str(file_list[j-1])+"/"+str(mp4_cctv_list[j-1][0])

    try : 
        # -------------------- 동영상 쪼개기 ------------------------------------------------------------   
        import cv2
        n=119  #동영상을 119개로 쪼개줄것임

        vidcap = cv2.VideoCapture(mp4_cctv)     
        total_frames = vidcap.get(cv2.CAP_PROP_FRAME_COUNT)
        frames_step = total_frames//n
        for i in range(n):
            #here, we set the parameter 1 which is the frame number to the frame (i*frames_step)
            vidcap.set(1,i*frames_step)
            success,image = vidcap.read()  
            #save your image
            globals()['col{}.jpg'.format(i)]= image
            #cv2.imwrite(globals()['./col{}.jpg'.format(i)],image)
            
            # 저장해줄 위치 지정해줌
            cv2.imwrite('./new2/col'+str(i)+'.jpg',image)
        vidcap.release()
        
        # -------------------- yolo ------------------------------------------------------------
        # Yolo 로드
        net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
        classes = []
        with open("coco.names", "r") as f:
            classes = [line.strip() for line in f.readlines()]
        layer_names = net.getLayerNames()
        output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
        colors = np.random.uniform(0, 255, size=(len(classes), 3))

        for k in range(119):  #수정 119로
            # 이미지 가져오기
            print('사진' ,k)
            img = cv2.imread("./new2/col"+str(k)+".jpg")
            img = cv2.resize(img, None, fx=0.4, fy=0.4)
            height, width, channels = img.shape

            # Detecting objects
            blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)
            net.setInput(blob)
            outs = net.forward(output_layers)

            # 정보를 화면에 표시

            class_ids = []
            confidences = []
            boxes = []
            for out in outs:
                for detection in out:
                    scores = detection[5:]
                    class_id = np.argmax(scores)
                    confidence = scores[class_id]
                    if confidence > 0.5:
                        # Object detected
                        center_x = int(detection[0] * width)
                        center_y = int(detection[1] * height)
                        w = int(detection[2] * width)
                        h = int(detection[3] * height)
                        # 좌표
                        x = int(center_x - w / 2)
                        y = int(center_y - h / 2)
                        boxes.append([x, y, w, h])
                        confidences.append(float(confidence))
                        class_ids.append(class_id)

            indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

            font = cv2.FONT_HERSHEY_PLAIN
            label_lists=[]
            for i in range(len(boxes)):
                if i in indexes:
                    x, y, w, h = boxes[i]
                    label = str(classes[class_ids[i]])
                    color = colors[i]
                    cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
                    cv2.putText(img, label, (x, y + 30), font, 3, color, 3)
                    label_lists.append(label)

            cv2.imshow("Image", img) 
            cv2.waitKey(1)
            cv2.destroyAllWindows()
            print(label_lists)
            df['mp4'][:][k]=label_lists


        #맥에서 opencv 안닫힐때 꿀팁
        cv2.destroyAllWindows()
        cv2.waitKey(1)
        cv2.waitKey(1)
        cv2.waitKey(1)
        cv2.waitKey(1)

 
    except :
        print('exept',file_list[j-1],j-1)

 

이 방법은 k-means 방법처럼, 클러스터 개수 가정해줄 필요가 없습니다. 또 이방법에서 주목한점이 군집간 거리를 활용하는 방법입니다.

.............................................................................................................................

  • 군집간 거리 측정 방식

-method : single, complete, average, centroid, ward linkage 방식이 존재

-Centroid : 두 군집의 중심점(centroid)를 정의한 다음 두 중심점의 거리를 군집간의 거리로 측정

-Single : 최단 연결법, 모든 데이터 조합에서 데이터 사이 거리를 측정해서 가장

최소 거리(작은 값)를 기준으로 군집 거리를 측정

-Complete : 최장 연결법으로 두 클러스터상에서 가장 먼 거리를 이용해서 측정하는 방식

-Average : 평균 연결법, 두 군집의 데이터들 간 모든 거리들의 평균을 군집간 거리로 정의(위에서 singe.complete를 합쳐준 방법이라하면 되겠다)

-Ward : 와드연결법은 군집분석의 각 단계에서 데이터들을 하나의 군집으로 묶음으로써 생기는 정보의 손실을 군집의 평균과 데이터들 사이의 오차제곱합(SSE)으로 아래와 같이 측정한다.

.............................................................................................................................

<코드부분>

Xi = np.array([[0,17,21,31,23],[17,0,30,34,21],[21,30,0,28,39],[31,34,28,0,43],[23,21,39,43,0]]) dists = squareform(Xi) #여기서 flat하게 바꾸어 주어야한다.이거 안해주고 넣으면 어딘가 이상해짐  Z = linkage(dists, method='single')  # method는 여기서 변경해주면 된다 dendrogram(Z)   # 아래 그래프 출력 plt.axhline(20, color='k', ls='--');  #임계치값(20)에 대해 점점이 가로줄을 그어줌

 

shc.fcluster(Z, 20, criterion='distance')  #임계치20에 줄을 그어서 나누어지는 군집들

→ [a,b][c][d][e] 이렇게 나누어짐을 확인할수 있습니다.

 

 

 

<개념부분>

첫번째줄에서, 임계값을 주지않으면, 총 1개의 군집이 출력됩니다. (method별로 만들어지는 dendrogram 모양이다릅니다)

두번쨰 줄에서 임계값을 줌으로써 여러개의 군집으로 나누어줄수 있습니다.

 

 

이것은 method 별로 유사도를 처리하는 방법이 다른것을 자세히 나타내 줍니다.

(single 은 가장 가까운 거리를 채택, complete 는 가장 먼거리를 채택, average는 이 두개의 평균을 채택합니다.)

e.g. single linkage 방법에서 abce, d 사이의 거리를 구할때, d와 ab간의 거리 31, d와 c간의 거리 28, d와 e간의 거리 43중에 가장 작은값인 28을 선택해줍니다. 만약 complete linkage 방법이였다면, 43을 선택해주었을것입니다.

(centroid , ward 이 두가지 메소드는 계산과정에서 (x,y)축을 필요로 하기 때문에 x,y축에서 pdist로 유사도를 구하는 방식이 아니라 처음부터 유사도를 집어넣어서 계산하는  방법에는 바람직하지 않음

 

 

 

 

 

 

 

 

참조

https://mambo-coding-note.tistory.com/284 - 개념참조

https://github.com/fmfn/BayesianOptimization - 코드참조

https://www.youtube.com/watch?v=sbbR-XRft9o&t=45s - 개념참조

베이즈 정리 간단히
  • 사전확률과 사후 확률사이의 관계를 나타내는정리

**사전확률/사후확률 : 어떤 일(evidence를 관측해서 갱신하하기 전/후의 내 주장에 관한 신뢰도

  • 새로운 정볼를 토대로 어떤 사건이 발생했다는 주장에 대해 신뢰도를 갱신해나가는 방법이다

**베이지안주의 관점 : 동전앞면이 나올확률은 50%, 100번동전을 던졌을때 앞면이 나왔다는 주장의 신뢰도가 50%라고 본다.

**빈도주의 관점 : 동전앞면이 나올확률은 50%, 100번동전을 던졌을때 50번은 앞면이 나온다고해석 (기존의 통계학)

  • 베이지안 관점의 통계에서는 사전확률과같은 경험에 기반한 선험적인,불확실성을 내포하는 수치를 기반을 하고 거기에 추가정보를 바탕으로 사전확률을 갱신한다.(귀납적 추론)

e.g.

질병 A의 발병률은 0.1%.이 질병이 실제로 있을 때 질병이 있다고 검진할 확률(민감도)은 99%, 질병이 없을 때 없다고 실제로 질병이 없다고 검진할 확률(특이도)는 98%라고 하자.

만약 어떤 사람이 질병에 걸렸다고 검진받았을 때, 이 사람이 정말로 질병에 걸렸을 확률은?

 

 

  • 한마디로 정의하면 : Random Search와 통계적인 기법 (Gaussian Distribution)을 기반으로 실제 data를 이용하여 surrogate model을 이용하여 실제 model을 찾지 않아도 Maximum value를 도출해낼 수 있다는것.

 

 

 

1. 지금까지 관측된 데이터 D = [(x1, f(x1)), (x2, f(x2)) … (xn, f(xn))]을 통해, Gaussian process prior로 function f(x)를 Estimation한다. (= surrogate model)

** Surrogate model(대체 모델, 근사수학모델)

이란 자동차 충돌 실험과 같이 제한된 계산 비용이 많이 드는 시뮬레이션을 기반으로 복잡한 시스템의 수많은 입출력 특성을 실제 모형과 유사하게 만드는 것

  • 여기서 f(x)는 함수이고, x는 하이퍼 파라미터이다!!!!!!!! (x가 여러개일수도 있음)

그러니까 앞에서 함수의 해당 하이퍼파라미터랑 , 탐색대상 함수를 쌍으로 만든다음, 이것을 대상으로 surrogaate model을 만들어서 평가를 순차적으로 업데이트하여 최적의 하이퍼파라미터조합을 탐색하는 과정

 


  • 관측치 수(코드에서 나오는데 n_iter로 몇번 반복할지 조정가능함) 가 증가함에 따라 사후 분포가 개선되고 알고리즘은 아래 그림에서 볼 수 있듯이 매개 변수 공간에서 탐색 할 가치가있는 영역과 그렇지 않은 영역이 더 확실해진다.(한마디로 위에 피피티 그림에서 회색부분 공간이 점점 줄어들고 대충 모양이 잡힌다는 뜻임)

(피피티 4개짜리 그래프 설명) 위 피피티에서 4개짜리 그림을 보면, 1번에서 모양이 살짝 바뀌었다. 두번째로는 제일 값이 높아보이는쪽으로 이동한다. 먼가 모양이 좀더 좁아졌다. 세번째로는 variance가 제일 높아보이는데로 이동했다. 이렇게 계속 반복반복하다보면 4번째 그림처럼 되고, 노란색 부분 즉 maximum값을 구할수있다.

→ 이렇게 Exploitation/Exploration 을 반복해주는 매커니즘이

acquisiton function

인것임 (용어는 뒤에....)

 

2. Function f(x)를 다음으로 관측할 지점 (xn+1, f(xn+1))으로 Acquisition Function(decision rule)으로 선택하여 이동한다.(제일 중요하다)

acquisition functio

n

은 surrogate model이 목적함수(우리가 찾고자하는 함수) 에 대해서 실제 데이터를 기반으로 다음번 조사할 x값을 확률적으로 계산해서 추천해주는 함수

**Exploitation 은 현재까지 조사된 값들의 근방으로 다시 조사를 하는 것이다. 착취를 말한다.

**Exploration 은 현재까지 조사된 값들의 근방으로 조사를 하지 않고, 불확실성이 제일 높은 구간을 조사한다. 탐험을 말한다.

<acquisition function 종류>

  1. EI (Expected Improvement / MEI 라고도함 )는 Exploration 과 Exploitation 방법을 모두 일정 수준 포함하도록 설계된 것이고, 제일 많이 쓰는 Acquistion Function이다.
  1. MPI
  1. UCB

!! acquisiton function 에 따라 성능이 달라진다 !!

 

<베이지안 옵티 코드!>

 

#!pip install Bayesian-Optimization
#https://github.com/fmfn/BayesianOptimization 참조

# underlying function!! , x,y를 하이퍼 파라미터 취급한다.
def black_box_function(x, y):
    return -x ** 2 - (y - 1) ** 2 + 1
from bayes_opt import BayesianOptimization
# Bounded region of parameter space
pbounds = {'x': (2, 4), 'y': (-3, 3)}   #하이퍼 파라미터 정해줌
optimizer = BayesianOptimization(  
    f=black_box_function, #앞에서 지정해준 black_box_funciton을 함수를 f에 넣어준다.
    pbounds=pbounds,  #하이퍼 파라미터 넣어준다.
    verbose=2, #verbose = 1 prints only when a maximum is observed, 0일땐 silent ,versbose=2 항상
    random_state=1,   #seed, 무작위성을 컨트롤 0이면,반복해도 똑같은값 출력함.
)
optimizer.maximize(
    init_points=2,  # init_points : 수행하려는 임의 탐색 단계 수. 무작위 탐사는 탐사 공간을 다양 화하여 도움을 줌.
    n_iter=3,  # n_iter :위에서 임의탐색한거 주위에서 찾아봄 (3.4, 3.5, 3.002, 2.7, 2.95 이렇게)
    acq='ei',  #aacquisition 선택 ( ei / poi / usb )  - 이것에 따라 성능이 갈리기도 한다.
)
# 임의 탐색2번 + 반복3번해서 총 5개 나오는것! 
>>
|   iter    |  target   |     x     |     y     |
-------------------------------------------------
|  1        | -7.135    |  2.834    |  1.322    |
|  2        | -7.78     |  2.0      | -1.186    |
|  3        | -7.11     |  2.218    | -0.7867   |
|  4        | -6.76     |  2.558    | -0.1028   |
|  5        | -17.39    |  4.0      | -0.5455   |
=================================================
print(optimizer.max)  # 가장 최대일때의 x,y값을 출력해준다.

>> 
{'target': -6.760373063273364, 'params': {'x': 2.558177239763734, 'y': -0.10277027219097953}}
for i, res in enumerate(optimizer.res):
    print("Iteration {}: \n\t{}".format(i, res))
    
>> 
Iteration 0: 
	{'target': -7.135455292718879, 'params': {'x': 2.8340440094051482, 'y': 1.3219469606529488}}
Iteration 1: 
	{'target': -7.779531005607566, 'params': {'x': 2.0002287496346898, 'y': -1.1860045642089614}}
Iteration 2: 
	{'target': -7.109925819441113, 'params': {'x': 2.2175526295255183, 'y': -0.7867249801593896}}
Iteration 3: 
	{'target': -6.760373063273364, 'params': {'x': 2.558177239763734, 'y': -0.10277027219097953}}
Iteration 4: 
	{'target': -17.38863150351646, 'params': {'x': 4.0, 'y': -0.5455198166042586}}
optimizer.set_bounds(new_bounds={"x": (-2, 3)})  #범위 수정해줌!!!!

optimizer.maximize(
    init_points=0,
    n_iter=5,
)   

>>
|   iter    |  target   |     x     |     y     |
-------------------------------------------------
|  6        | -1.769    | -1.57     |  1.552    |
|  7        | -1.362    | -1.438    |  1.542    |
|  8        | -1.447    | -1.395    |  1.708    |
|  9        | -0.6024   | -1.143    |  1.543    |
|  10       |  0.1307   | -0.8744   |  1.324    |
=================================================
optimizer.probe(  #probe는 탐색을 의미함
    params={"x": 0.5, "y": 0.7},
    lazy=True,  #기본으로 설정해놓는다.
)
#다음에 maximize를 호출할 때 평가함

optimizer.probe(
    params=[-0.3, 0.1],
    lazy=True,
)

# Will probe only the two points specified above
optimizer.maximize(init_points=0, n_iter=0)

>>
|   iter    |  target   |     x     |     y     |
-------------------------------------------------
|  13       |  0.1      | -0.3      |  0.1      |
|  14       |  0.1      | -0.3      |  0.1      |
=================================================

 

 

#피처들 목록
'Device_AddN', 'Device_AddV2', 'Device_ArgMax',
       'Device_AssignAddVariableOp', 'Device_BiasAdd', 'Device_BiasAddGrad',
       'Device_Cast', 'Device_Conv2D', 'Device_Conv2DBackpropFilter',
       'Device_Conv2DBackpropInput', 'Device_DivNoNan', 'Device_DynamicStitch',
       'Device_Equal', 'Device_FusedBatchNormGradV3',
       'Device_FusedBatchNormV3', 'Device_LogicalAnd', 'Device_MatMul',
       'Device_MaxPool', 'Device_MaxPoolGrad', 'Device_Mul', 'Device_RealDiv',
       'Device_Relu', 'Device_ReluGrad', 'Device_ResourceApplyGradientDescent',
       'Device_Softmax', 'Device_SoftmaxCrossEntropyWithLogits', 'Device_Sum',
       'Device_Tile', 'Device_Unknown', 'Device__FusedConv2D',
       'Device__HostRecv', 'Host_FlushSummaryWriter', 'Host_IteratorGetNext',
       'Host_LogicalAnd', 'Host_WriteSummary', 'Device_AvgPool',
       'Device_AvgPoolGrad', 'Device_Square', 'Device_Mean',
       'Device_BroadcastTo'

  • Device_AddN

모두 더해서 출력한다

x = [9, 7, 10]
tf.math.add_n(x) ==> 26
  • Device_AddV2

요소별로 x + y 출력

tf.raw_ops.AddV2(x, y, name=None)
  • Device_ArgMax

전체 행렬에 대해 계산되어 단일 숫자를 반환함 (=몇번째가 제일큰지)

tf.raw_ops.ArgMax(
    input, dimension, output_type=tf.dtypes.int64, name=None
)
from numpy import argmax
vector = [0.4, 0.5, 0.1]  # define vector
result = argmax(vector)  # get argmax
print('arg max of %s: %d' % (vector, result))
>>arg max of [0.4, 0.5, 0.1]: 1  #1[0th,1th,2th]중 두번째값(0.5)이 젤 크다는뜻
probs = asarray([[0.4, 0.5, 0.1], [0.0, 0.0, 1.0], [0.9, 0.0, 0.1], [0.3, 0.3, 0.4]])
print(probs.shape)
result = argmax(probs, axis=1)
print(result)
>>(4, 3)[1 2 0 2] 

참조 : https://deeplizard.com/learn/video/K3lX3Cltt4c

  • AssignAddVariableOp

변수에 현재값을 추가

tf.raw_ops.AssignAddVariableOp(resource, value, name=None)

  • Device_BiasAdd

bias 와 value 를 더해준다.

-scope: A Scope object

-value: Any number of dimensions.

-bias: 1-D with size the last dimension of value.

tf.raw_ops.BiasAdd(value, bias, data_format='NHWC', name=None)

  • BiasAddGrad

The backward operation for "BiasAdd" on the "bias" tensor.

tf.raw_ops.BiasAddGrad(out_backprop, data_format='NHWC', name=None)

  • Device_Cast

x.values를 dtype으로 변환

tf.cast(x, dtype, name=None)
x = tf.constant([1.8, 2.2], dtype=tf.float32)
tf.dtypes.cast(x, tf.int32)

# float32 -> int32로 변환해주었다.

  • Device_Conv2D
Conv2D(32, (5, 5), padding='valid', input_shape=(28, 28, 1), activation='relu')

순서대로, 필터수, (행,열) , padding:경계처리방법

'valid'는 유효한 영역만 출력 / 'same' 출력 이미지 사이즈가 입력 이미지 사이즈와 동일

input_shape : 샘플수를 제외한 입력형태를 정의, 첫 레이어일떄만 정의해주면됨 (행,열,채널수)

activation : 활성화 함수 설정

‘linear’ : 디폴트 값, 입력뉴런과 가중치로 계산된 결과값이 그대로 출력으로 나옴 / ‘relu’ : 은닉층에 주로 쓰임 / ‘sigmoid’ : 이진 분류 문제에서 출력층에 주로 쓰임 / ‘softmax’ : 다중 클래스 분류 문제에서 출력층에 주로 쓰임

  • Device_Conv2DBackpropFilter

필터 에 대한 컨볼루션의 gradients를 구함

tf.raw_ops.Conv2DBackpropFilter(
    input, filter_sizes, out_backprop, strides, padding, use_cudnn_on_gpu=True,
    explicit_paddings=[], data_format='NHWC', dilations=[1, 1, 1, 1],
    name=None
)

input : 텐서! [배치,인풋높이, 인풋너비, 인풋채널] 이런 모양이어야한다.

filter_sizes : int32모양의 정수벡터여야함, [높이,너비,인풋채널,출력채널]

out_backprop : 텐서 [배치.출력높이,출력너비,출력채널] 모양

strides : 필터가 이동할간격

padding : "SAME", "VALID", "EXPLICIT"

use_cudnn_on_gpu : optional. true가 디폴트

explicit_paddings : 앞에서 패딩이 EXPLICIT 일때, the list of explicit padding amounts

data_format : NHWC가 디폴트

# NHWC
output[b, i, j, k] = sum_{di, dj, q} input[b, strides[1] * i + di, strides[2] * j + dj, q] * filter[di, dj, q, k]
  • Device_Conv2DBackpropInput

input 에 대한 컨볼루션의 gradients를 구함

tf.raw_ops.Conv2DBackpropInput(
    input_sizes, filter, out_backprop, strides, padding, use_cudnn_on_gpu=True,
    explicit_paddings=[], data_format='NHWC', dilations=[1, 1, 1, 1],
    name=None)
  • Device_DivNoNan

리턴값 : The z tensor.

tf.raw_ops.DivNoNan(x, y, name=None)
  • Device_DynamicStitch

데이터로부터 텐서를 단일 텐서로 interleave해준다

**interleave : http://www.terms.co.kr/interleave.htmhttp://www.terms.co.kr/interleave.htm

성능을 높이기 위해서 데이터가 서로 인접하지 않도록 배열하는바업.

tf.raw_ops.DynamicStitch(indices, data, name=None)
  • Device_Equal

x,y 가 같은지 리턴해줌

tf.math.equal(x, y, name=None)
  • Device_FusedBatchNormGradV3

배치 정규화를 위한 기울기

4D Tensor의 크기는 "NHWC"또는 "NCHW"로 정의한다 (data_format)

tf.raw_ops.FusedBatchNormGradV3(
    y_backprop, x, scale, reserve_space_1, reserve_space_2, reserve_space_3,
    epsilon=0.0001, data_format='NHWC', is_training=True, name=None)
  • Device_FusedBatchNormV3

배치 정규화

tf.raw_ops.FusedBatchNormV3(x, scale, offset, mean, variance, epsilon=0.0001, exponential_avg_factor=1,data_format='NHWC', is_training=True, name=None)
  • Device_LogicalAnd

x and y 의 truth을 리턴함

  • Device_MatMul

dot이랑 비슷하다. 곱셈을 의미함


  • Device_MaxPool

  • Device_MaxPoolGrad

맥스풀링함수에서의 gradients를 계산함

tf.raw_ops.MaxPoolGrad(orig_input, orig_output, grad, ksize, strides, padding, explicit_paddings=[],data_format='NHWC', name=None)
  • Device_AvgPool

  • Device_AvgPoolGrad

average pooling functino 에서 gradients를 구한다


  • Device_Mul

곱셈 x * y 값을 리턴

  • Device_RealDiv

x/y 값을 리턴함


  • Device_Relu

Same shape as the input.

tf.keras.layers.ReLU(max_value=None, negative_slope=0, threshold=0, **kwargs)
  • Device_ReluGrad
tf.raw_ops.ReluGrad(gradients, features, name=None)
  • Device_ResourceApplyGradientDescent

알파와 델타를 뺴고 var을 업데이트한다.

  • Device_Softmax

활성화함수, 입력받은 값을 출력으로 0-1사이의 값을 모두 정규화하며,출력값들의 총합은 항상1

  • Device_SoftmaxCrossEntropyWithLogits

소프트맥스 교차 엔트로피의 cost와 gradients 를 계산하여 역전파한다.

tf.raw_ops.SoftmaxCrossEntropyWithLogits(features, labels, name=None)

  • Device_Sum

텐서 차원에서 모든 요소들의 합을 계산한다.

tf.raw_ops.Sum(input, axis, keep_dims=False, name=None)
  • Device_Tile

주어진 텐서를 타일링하여 새 텐서를 만들어낸다

e.g. tf.tile([a,b,c,d]) → [a,b,c,d,a,b,c,d] 이런 텐서를 얻을수가 있다.

  • Device_Unknown

unknown shpae ⇒ TensorShape(None), TensorShape([None, 256]) ....

  • Device__FusedConv2D

Conv2D의 data_format 속성은이 작업에서 지원되지 않으며 대신 'NHWC'순서가 사용됨. 내부적으로이 작업은 그래프 당 단일 스크래치 버퍼를 사용하므로 여러 버전이 병렬로 실행되는 경우 차단된다. 이것은이 연산자가 주로 메모리 사용을 최소화하기위한 최적화이기 때문이다.

  • Device__HostRecv
  • Host_FlushSummaryWriter
tf.summary.flush(writer=None, name=None)
  • Host_IteratorGetNext

주어진 Iterator에서다음 출력을 가져옴

tf.raw_ops.IteratorGetNext(iterator, output_types, output_shapes, name=None)
  • Host_LogicalAnd

Device_LogicalAnd 과 곂침

  • Host_WriteSummary

텐서의 summary를 적는다.

tf.raw_ops.WriteSummary(writer, step, tensor, tag, summary_metadata, name=None)
  • Device_Square

x안에 있는 요소들을 제곱으로 만들어준다

tf.math.square([-2., 0., 3.])[4., 0., 9.]
  • Device_Mean

평균을 구해준다. 예를들어서, 만약 value들이 [1, 3, 5, 7] 라고 하면 mean 은 4

  • Device_BroadcastTo

산술연산을 위해 호환되는 모양을 갖도록 배열을 만드는 프로세스.

x = tf.constant([1, 2, 3]) 
y = tf.broadcast_to(x, [3, 3]) 
print(y)
>> tf.Tensor( [[1 2 3] [1 2 3] [1 2 3]], shape=(3, 3), dtype=int32)

< 시도해본 차원축소 방법 리스트 >

  • pca
  • kernal pca
  • svd
  • isomap
  • mds
  • t-sne

 

차원축소를 해주는 이유

— 차원의 저주문제 (오버피팅)

— 데이터 압축

— 계산비용축소

 

차원축소 접근방법 2가지

(1) 투영 (projection) — PCA /SVD/

(2) 매니폴드학습 / 대부분 but 항상 통하지는 않는다.— Kernal PCA / Isomap / T-SNE /

e.g. 스위스롤 ( 다 펼치면 2d , 하지만 3차원으로 말려있다)

 

→ 전자는 매니폴드 학습방법이 더 효율적 , 후자는 비효율적

⇒ 모델을 학습전 학습 데이터셋 차원축소를 시도하면 항상 모델의 성능은 항상 더 낫거나 간단한 모델이 되는 것은 아니다

 

** 매니폴드란!

일반적으로 거리를 구하는 공식 (지금까지 배워온 방식) = 유클리디안 방식

매니폴드(manifold)란, 두 점 사이의 거리 혹은 유사도가 근거리에서는 유클리디안(Euclidean metric, 직선 거리) 을 따르지만 원거리에서는 그렇지 않은 공간을 말합니다.

그림처럼, 조그만 유클리디안 공간 조각들(육면체 하나를 근거리에서 정의된 유클리디안 공간이라고 생각하시면 됩니다)이 다닥다닥 붙어 이루어져서 전체적으로 보면 비유클리디안(non-Euclidean)이 되는 공간을 뜻합니다. 아래 그림은 각각 2차원과 3차원 매니폴드를 나타냅니다.

 

[PCA]

PCA : 차원을 줄이되 정보손실을 최소화한다

  • 원래 공간에서 데이터가 퍼져 있는 정도를 축소된 공간에서 얼마나 잘 유지하느냐를 척도로 삼음
  • 이를 잘 유지하냐는 변환된 공간에서의 데이터의 '분산'으로 측정
  • 변환된 공간에서 데이터의 분산을 최대로 할 수 있는 좌표축을 찾아야함 ( 즉 데이터가 분산되어 있는 주요한 방향(Principal direction)을 찾아준다

step1 데이터투영(projection)하기

원래 2차원이였다면 1차원으로 투영해버리기

 

step2: 투영된 공간에서 분산 측정하기

평균과 분산을 정규화 해준다. 정규화 해주면 각각의 attribute의 평균이 0이되고, 분산이 1이 되기 때문에 ( 즉 같은 scale을 같는다) attribute간의 비교가 가능해진다. 아래 그림을 살펴보면 분산이 최대가 되어야 데이터가 많이 보존됨을 알수있다. (제일 첫번째 그림에서 c1)

e.g. 첫번째 그림은 주성분이 1개일때(c1) / 두번째 그림은 주성분이 3개일때 (e1,e2,e3 순서대로 분산이큼)

 

step3: 분산의 최대치는 어떻게 찾는가

투영된 공간에서 분산을 최대화 해 줄 수 있는 벡터 u를 찾아야한다. u는 방향이 중요하다. (계산할때 라그랑지 승수를 사용한다)

 

**

공분산행렬

이란? (뒤에서 SVD 와 비교할때도 사용됨)

  • 다음 그림과같이 공분산 행렬은 각 속성에 대해서 두개의 속성(특징쌍)의 변동이 얼마나 닮았는가 ( = 얼마만큼이나 함께 변하는가를 행렬로 나타내준다. 이때 정방행렬이라는것에 주목해야한다( 뒤에 svd와 비교 )
  • 공분산행렬에서 고유값과 고유벡터를 구할수 있다.
  • 이렇게 구한 고유값 목록에서 주성분을 뽑아낼수 있다.

 

#주성분을 2개로 지정해주었을때, 
#위의 결과의 의미는 원 데이터셋 분산의 99.5%가 첫 번째 주성분 축에 놓여 있고, 
# 0.3%가 두 번째 주성분 축에 놓여 있다는 것을 말합니다. 

> pca.explained_variance_ratio_
array([0.99541373, 0.00338148])
> sum(pca.explained_variance_ratio_)
0.9987952108914363
# 두속성이 전체 변화량의 99%를 차지

한마디로 PCA는 데이터의 분산을 최대한 보존하면서 서로 직교하는 새 축(새 기저)를 찾아, 고차원 공간의 표본들을 저차원 공간으로 변환하는 기법이다 / 데이터 하나 하나에 대한 성분을 분석하는 것이 아니라, 여러 데이터들이 모여 하나의 분포를 이룰 때 이 분포의 주 성분(=데이터들의 분산이 가장 큰 방향벡터)을 분석해 주는 방법이다.

 

[Kernal PCA]

pca 는 차원축소를 위한 선형 변환 기법을 이용하기 떄문에 선형으로 분리 불가능한 데이터에 대해서는 적당하지 않다. 이를 극복하기 위해 커널 pca 를 사용할수 있다.

  • 아래 그램에서 첫번째 선형적인 데이터에서는 pca가 잘 작동하지만 2,3 번째 데이터처럼 비선형적인 데이터의 경우 적용하기 곤란하다.

 

코드 (아래) -(1)(2) 예제

http://203.246.113.170:8800/notebooks/Yoonseo/kernal pca 예제 비선형데이터셋.ipynb

 

(1) e.g. 반달 데이터셋 사용! (make_moon)

  • 아래 그림에서 (좌) pca 적용 (우) kernal PCA 적용

 

(2) 나선형 데이터 사용 (make_circles)

  • 두번째 그림이 pca 적용 / 세번째 그림이 kernal pca 사용

 

 

(3) 그외 여러가지 비선형 데이터에서 PCA vs KPCA 비교분석된 좋은 자료

https://rpubs.com/sandipan/197468

[SVD]

특이값 분해라고도 한다

특이값 분해는 고유값 분해 처럼 행렬을 대각화하는 한 방법이다. 그런데, 특이값 분해가 유용한 이유는 행렬이 정방행렬이든 아니든 관계없이 모든 m x n 행렬에 대해 적용 가능하기 때문.

앞서서 PCA 는 고유값 분해는 기본적으로 정방행렬을 반드시 필요로하며, 새로운 축을 만들어 고유벡터의 새로운 관점으로 바라보는것이였다면, SVD 는 정방행렬이 아니라 직사각형 행렬일떄 사용한다.

직사각행렬에 연산을 취했을때 벡터의 방향만 변하고 양(길이)는 변하지 않는다.

https://commons.wikimedia.org/wiki/File%3ASingular_value_decomposition.gif (움직이는 모양 확인)

 

[MDS]

MDS 는 1964 년에 제안된, 매우 오래된 임베딩 방법. MDS 기법은 numeric 변수로만 이루어 졌을 때에만 사용이 가능하다.

낮은 차원에서의 자료들이 거리가 멀리 떨어져 위치한다는 것은 비유사성이 높다는 뜻이고, 자료가 가까울수록 비유사성이 낮다 (즉 유사성이 높다)는 뜻이 된다. MDS를 이용하여 데이터를 시각화 하는 방법의 가장 큰 장점은 바로 데이터들의 유사도를 확인할 수 있다는 점이다. (비슷한 변수값을 가지는 데이터들은 가까이 있다)

한마디로 개체들을 2차원 또는 3차원 공간상에 점으로 표현하여 개체들 사이의 집단화를 시각적으로 표현하는 분석 방법. 군집분석은 개체들간의 비유사성을 이용하여 동일한 그룹들로 분류하는것이 목적인것에 반해 mds는2,3차원위에 점으로 표현하고 시각화하는것이 주 목적. pca 와 비교하면, 원데이를 최대한 보존한다.

 

분석 과정

(1) 자료수집

n개의 개체들을 대상으로 p개의 특성을 측정한다

(2) 유사성 / 비유사성 측정

mds 에서는 유사성이아니라 비유사성 측정방법을 사용함 ( 이유 - 유사성 대신에 비유사성(또는 거리)를 이용하는 이유는 유사성의 경우 대각선원소의 값을 정의하기 어렵기 때문이라고 한다)

(3) 2차원, 3차원 공간상에 개체를 표현

개체들 사이의 *유클리디안 거리(직선거리 계산방법) 를 비유사성 행렬을 이용해서 개체들을 2차원 공간상 점으로 표현한다.

**비유사성 행렬 = m개 객체로 구성된 데이터 세트의 경우, 데이터 세트에 m*(m – 1)/2개 쌍이 있다.

(4) 최적 표현의 결정

s-stress 를 사용해서 최적위치의 적합성을 측정한다.

오른쪽은 stress 구하는 방식 (dij 는 점i 부터 점 j 까지의 실제 유클리디안거리, ^dij는 프로그램에 의해서 추정된 거리)

 

[ISOMAP]

이는 kernal pca 처럼 비선형 데이터를 다룰때 유리하다

이는 MDS + PCA 각각의 특징을 합친 방법이다.

e.g. 스위스롤

앞선 방식 MDS를 사용하면 아래 그림에서 두점사이의 거리는 매우 짧다. 하지만 isomap에서는 다른 방식을 사용한다. 거리를 측정할때 인접지점을 고려한다. 한마디로 쭉 이어져야한다.

e.g. 지구에서 나라별 거리 계산방식과 같다. 각 나라별로 거리를 측정할때 mds 방식으로 유클리디안 방식으로 측정하면 내핵을 뚫고 들어가야한다. 하지만 실제로 계산할땐, 지구의 표면을 따라 거리를 계산한다 (=isomap)

I

[T-SNE]

 

 

 

 아래는 발표 피피티 ( 여기없는건 발표자료에 있음)

https://docs.google.com/presentation/d/1ajWFe_v5EUz-y70otmEQLzr-vn47PXSh3npDBiYV6Hs/edit?usp=sharing 

 

차원축소_발표

차원 축소 개념과 이해 발표자 허윤서

docs.google.com

 

+ Recent posts