OmniAICreator/Qiita-1.07M huggingface dataset:
メガビットの波に飲み込まれて、メガビットの海で溺れて、必死に踠いた結果、たどり着いたのは……。

#お久しぶりです！

半年間が終わりました。
皆さん、お久しぶりです！
改めまして、お久しぶりです田川 宗慶です！

前回はジーズアカデミーのアドベンドカレンダーに参加した記事を書きましたね。そのときはジーズアカデミーに入学した理由やプログラミングを始めた理由を書いたような気がしています。ということで、田川は半年間ほどプログラミングを学んでいました。


学んでいた？正確には学んでいたという表現はちょっと違うんですけど、分かりやすくいえば学んでいました。



2022年の10月から半年間は毎日毎日、明くる日も明くる日もコードというプログラミングの文字と向き合う毎日でした。


#チーズアカデミーという壁

チーズアカデミーという伝統的な作品を作る。
これが一番最初の課題でした！

チーズアカデミーという架空のがチーズ職人養成学校のポートフォリオサイトを見本を元に作成していくわけですが、プログラミングどころかパソコンすら初心者の田川からしてみると、これを作っているときが一番地獄だったと思います。


教材となる動画は1動画につき20回は見て、ちょっと戻して見てを繰り返して、提出出来たときには嘘じゃなく魂が口から出かけていたと思います。

その後もさまざまなプログラミング言語を学ぶたびに新しい課題が提示されて、宿題として作成→提出を繰り返していきました。


##javascript……php……Laravel………。

積み重ねていくと色々なことがわかるようになってくるわけですが、それと同時に周りとの格差をより一層感じるようになりました。


元々、周りの同期から比べても劣っていることは承知の事実で自分自身でも受け止めて、受け入れていたんですが、やればやればほどにそのことがズシンズシンと精神的にボディーブローとして効いていくわけです。



#それでも逃げなかったこと。

それでも半年間逃げなかったこと、走り抜けることが出来たのも周りの同期である仲間や日々助けてくれた先輩やスタッフがいたことです。


ダメダメでどうにもならない状態であっても、見捨てずに見放さずにいてくれたことが心強く感じていました。


卒業するには卒業制作を提出するんですが、
その準備は授業過程が半分くらい過ぎたころからずっと考えていたものを作成することにしました。


ただ、考えているものをきちんとした形に作り出すことはとてつもないことだと、作り出してから気づくんです。


と書いている辺りで、なんか脱線しそうなので
卒業制作したものについては改めて書こうと思います！


卒業制作で作りたいものは前回の記事でも少し触れていましたが、そのアイデアから導き出して、その前段階になるものを作ることにしたんですが、それがなかなか大変でしたので上にも書いたとおり改めてm(_ _)m


まずはとりあえず、無事卒業することが出来ました。という報告です！


プログラミングに関しては卒業したあと、
今も毎日触れていますし、これからも続けていこうと思っています。


なんか中途半端な記事ですが、
最後まで読んで頂き、ありがとうございます
m(_ _)m
それではまた。
ChatGPT 基礎テクニック

<h1>プロンプト作成の基礎テクニック

gpt-3.5よりもgpt-4の方がいい
なぜなら、3.5でできていたものでも、4で解決する場合があるから、
課金しよかな

<h2>出力形式を示す

出力形式:
トピック1:<トピック名1>
- <ポイント1>

..トピック2:<トピック名2>
-<ポイント2>

..
トピック10: ..

こんな形で出力形式を指定するといいです
個人的に、「出力形式:」から始まることでgptがそれを出力形式だなと認識してくれると思うので、この形式で出力形式を明示しようと思いました。


<h2>「###」で指示文を区切る

###で指示文と別の文を、ChatGPTに違うということを示してあげる必要があります。
GPTに改行などで文と文の区切りを示していたつもりだったが、うまくいかないことが多々ありました。

「###」で区切って示してやる必要があったのかと！驚き

特に良さそうなプロンプトエンジニアのプロンプトを見ていると、「###」がよくあるので尚更納得いきました。


<h2>代替案を具体的に提示

「興味関心などの情報は聞かず、対応マニュアルを作って」といってもその命令を無視することがあります
聞くなというだけでなく

「興味関心などの情報は聞かず、対応マニュアルを作って。
もしおすすめできる映画がない場合はご質問に答えられません」

というようにして代わりに何をすべきか具体的に明示するとうまくいく可能性が上がるようです
#2 データ収集(ハンドジェスチャーでドローンを操作する)

作成するシステムのためのデータ収集器を作成していきます。

必要な環境
・Pythonを実行する環境(本記事ではAnacondaで実行する)
・OpenCV

## 1.Anacondaで仮想環境の作成

仮想環境の作成

```Windows:Anaconda Powershell Prompt
conda create -n 仮想環境の名前
```

仮想環境の起動
```Windows:Anaconda Powershell Prompt
conda activate 仮想環境の名前
```
## 2.OpenCVなどのインストール(自分はjupyter labのインストールも行った)
インストールができたかを確認するためにAnaconda Powershell PromptでPythonの対話モードを起動し、import cv2とcv2.__versionと入力してもらうとインストールの有無とOpenCVのバージョンの確認ができます。Import cv2の時点でエラーを吐く場合はインストールができていないので再度インストールを試みてください。

OpenCVのインストール
```Windows:Anaconda Powershell Prompt
conda install opencv
```

## 3.コードの作成
今回のデータ収集器はデータセットを作成する為のものです。そのため、データセットの作成がしやすいように作成していこうと思います。

ファイル名の頭文字2つを分類のクラス番号とし「-」を挟んでファイル番号にしていこうと思います。「-」を入れるのはデータセットの読み込みの時にあると便利な為です。
フォルダ構成は以下の予定です。

![データセット構成.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3336392/2a030a43-d048-b81c-9078-0fa3b8cd6eb2.jpeg)

上記のフォルダ構成をもとに以下のコードを作成しました。
収集するクラス毎に起動して収集するようにしています。

```python
import cv2
import os
import glob

cap = cv2.VideoCapture(0)

#分類のクラスとして使用する
input_class = int(input('Input only integer : '))

while True:
    ret,frame = cap.read()
    
    cv2.imshow("CAMERA",frame)
    
    input_key = cv2.waitKey(1) & 0xff
    
    # ESCで終了
    if input_key == 27: 
        break 
        
    #画像の保存
    if input_key == ord('s'):
        
        #input_classの名前のフォルダが存在するか確認
        class_path = './' + str(input_class)
        
        
        if os.path.isdir(class_path) == True: #存在した場合
            all_file = glob.glob(class_path + '/*.jpg')
            file_num  = len(all_file) + 1 #フォルダ内のファイル数の取得
            
        else:
            os.mkdir(class_path)
            file_num = 1
            
        
        print(file_num)
        save_path = './' + str(input_class) + '/' + str(input_class) + '-' + str(file_num).zfill(4) + '.jpg'
        size = (64,48)
        resize_frame = cv2.resize(frame,size)
        cv2.imwrite(save_path,resize_frame)
        
        

cv2.destroyWindow("CAMERA")  
```
Go言語でgzipファイルを解凍したい

Go言語では標準ライブラリだけで、gzipファイルを解凍することができます。

以下は`./access.log.gz`ファイルを解凍し、`./access.log`に保存するサンプルコードです。

```go
srcPath := "./access.log.gz"
dstPath := "./access.log"

src, err := os.Open(srcPath)
if err != nil {
	panic(err)
}
defer src.Close()

gr, err := gzip.NewReader(src)
if err != nil {
	panic(err)
}
defer gr.Close()

dst, err := os.Create(dstPath)
if err != nil {
	panic(err)
}
defer dst.Close()

if _, err := io.Copy(dst, gr); err != nil {
	panic(err)
}
```

**環境情報**

```
$ go version
go version go1.19 linux/amd64
```
【ガチめにメモ】今年の個人目標は会社付近のランチに特化した社員向けの口コミサイトを作りたい

今年もアプリ制作を会社の個人目標にしちゃったので、まずはテーマを決めてみました。
忘れないうちに必要なのメモ。
メモなので実際の技術力・知識とはまた別の話で

# 【口コミ投稿サイトに必要な機能】

## マップ表示機能
　- django-leafletというライブラリを利用して、地図上に店舗の位置を表示する。

## 口コミ投稿機能
　- django-formsを利用して、新規の口コミ情報をデータベースに登録するフォームを作成する。
　- django-leafletを利用して、登録された口コミ情報をマップ上に表示する。

## 口コミ編集・削除機能
　- django-crudbuilderやdjango-crispy-formsなどのライブラリを利用して、編集・削除機能を実装する。

## 画像投稿機能
　- django-storagesというライブラリを利用して、S3などのストレージサービスに画像を保存する。
　- django-imagekitというライブラリを利用して、画像のリサイズやトリミングなどの加工を行う。

## マイページ機能
　- django-allauthというライブラリを利用して、ユーザー認証やソーシャルログインの実装を行う。
　- django-crispy-formsを利用して、マイページのフォームを作成する。

# 【開発に必要な技術】

## フロントエンド
　- Djangoのテンプレート言語やJavaScriptを利用して、HTML/CSSとの連携を行う。

## サーバーサイド
　- Djangoフレームワークを利用して、アプリケーションの構築を行う。
　- データベースには、Djangoが提供するORMを利用することが一般的。

## データベース
　- DjangoのORMを利用して、モデルを定義する。
　- データベース設計やSQL文の知識は必要ありませんが、ORMの基礎的な知識は必要です。
viコマンドの使い方

viコマンドは、UNIX系オペレーティングシステム上で動作する、強力で柔軟性の高いテキストエディタです。本記事では、viコマンドの基本的な使い方を紹介します。

## viコマンドを開く
ファイルを開くには、以下のコマンドを使用します。

```bash
vi [ファイル名]
```
ファイルが存在しない場合、新しいファイルが作成されます。

## モードの切り替え
viコマンドには主に2つのモードがあります。

1. `コマンドモード`：キーを押すことで各種コマンドを実行できます。
2. `インサートモード`：キーを押すことでテキストを入力できます。
デフォルトでは`コマンドモード`で開始されます。インサートモードに切り替えるには、`i キー`を押下します。
コマンドモードに戻るには、`Esc キー`を押します。

## 基本的な操作方法
コマンドモードで、以下のキーを使用してカーソルを移動できます。

`h`：左へ移動
`j`：下へ移動
`k`：上へ移動
`l`：右へ移動
もしくは矢印キーでも移動は可能です！
## テキストの編集
以下は、テキスト編集に関する基本的なコマンドです。

`i`：カーソル位置にテキストを挿入（インサートモードへ移行）
`a`：カーソルの次の位置にテキストを挿入（インサートモードへ移行）
`dd`：カーソルのある行を削除
`yy`：カーソルのある行をコピー
`p`：カーソルのある行の下に、コピー/カットされた行をペースト
## 検索と置換
コマンドモードで、以下のコマンドを使用して検索と置換を行うことができます。

`/[検索文字列]`：検索文字列を前方検索
`?[検索文字列]`：検索文字列を後方検索
`:%s/[検索文字列]/[置換文字列]/g`：検索文字列を置換文字列で一括置換

## ファイルの保存と終了
以下のコマンドを使用して、ファイルの保存や終了を行うことができます。

`:w`：ファイルを保存
`:q`：viを終了（未保存の変更がある場合はエラーが表示されます）
`:q!`：未保存の変更を破棄してviを終了
`:wq` または :x：ファイルを保存してviを終了
## まとめ
そもそもコマンドでの操作ってあまり馴染みがないですよね、、
慣れればなかなかにやりやすい（とは言うもののUIでの操作のほうが断然やりやす、、、）と思うので地道に慣れていきましょう！
TriloTrackerをEmuliciousで動かす

# TriloTrackerをダウンロード
https://github.com/cornelisser/TriloTracker

# Emuliciousをダウンロード
https://emulicious.net/
リリースから.zipと.dskファイルを落とす

# Emuliciousの設定
https://github.com/cornelisser/TriloTracker/blob/master/documentation/emulation_emulicious.md
を参考に
実行ファイルを開いてOption>Emulation>MSX>から各々設定
ModelをMSX2に設定しておく

# 実行
最初に落とした.dskファイルをFileから開く(もしくはドラッグアンドドロップ)ことで実行

# サンプルを再生する
F5キーでファイルダイアログを開いて選択
F1 or Enterで再生
ESCで停止
Homeで最初の再生位置に戻せる
Zshで、プロンプトをカスタムしたらコマンド入力位置がずれた

# はじめに
Zshユーザーです。
カスタムプロンプトを作るのが好きで、Bashとかでもちょくちょくカスタマイズしてました。
そんなときに出会ったバグです。

# 問題
Zshで、 **長めのコマンドを入力しようとすると、コマンドの入力位置がずれる。**
```zsh
source ~/.git-prompt.sh
GIT_PS1_SHOWDIRTYSTATE="yes"
GIT_PS1_SHOWSTASHSTATE="yes"
GIT_PS1_SHOWUNTRACKEDFILES="yes"
GIT_PS1_SHOWUPSTREAM="yes"
precmd (){
	if [ $? -eq 0 ] ;then
		PROMPT=$'\e[01;94mzsh %n@%m '$(__git_ps1 " (%s)")$'\n\e[01;36m%~ \e[01;33m%#\e[00m '
	else
		PROMPT=$'\e[01;94mzsh %n@%m '$(__git_ps1 " (%s)")$'\n\e[01;36m%~ \e[01;91m%#\e[00m '
	fi
	if [ ${VIRTUAL_ENV:-} ] ;then
		ENVNAME=${VIRTUAL_ENV##*/}
		PROMPT="($ENVNAME) $PROMPT"
	fi
}
```
こんな内容でした。
こうすると、長めのコマンドを入力すると、 **20文字程度までは入力できましたが、その後ずれました。**（再現できなかった。なんでかわからん。怖い。）

以下、無理やり再現。

```text:再現
~ % curl -sLo https://rcurl -sLo https://raw.githubusercontent.com/...
   |------------------|--------------------------------------------...
    ここまでは普通        表示がずれて前半20文字が残ったまま先頭から表示される
```

# 対処法
いろいろ試してみた結果、**エスケープシーケンスをBash由来のものではなくZsh固有のもの（```\e[00m```ではなく```%F{00}%f```）にしたら直った**っぽいです。

以下修正版
```zsh
source ~/.git-prompt.sh
GIT_PS1_SHOWDIRTYSTATE="yes"
GIT_PS1_SHOWSTASHSTATE="yes"
GIT_PS1_SHOWUNTRACKEDFILES="yes"
GIT_PS1_SHOWUPSTREAM="yes"
precmd (){
	if [ $? -eq 0 ] ;then
		PROMPT=$'%B%F{12}zsh %n@%m '$(__git_ps1 " (%s)")$'%f\n%F{6}%~%f %F{3}%#%f%b '
	else
		PROMPT=$'%F{12}zsh %n@%m '$(__git_ps1 " (%s)")$'%f\n%F{6}%~%f %F{9}%#%f '
	fi
	if [ ${VIRTUAL_ENV:-} ] ;then
		ENVNAME=${VIRTUAL_ENV##*/}
		PROMPT="($ENVNAME) $PROMPT"
	fi
}
```

このプロンプトは自由に使っていただいて構いません。```~/.git-prompt.sh```に、 https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh を置いとけばうまく動きます。
Ubuntu VM のセキュアブートの有効化

## はじめに

この記事では、[記事: Ubuntu VM の移行 (VMware から Hyper-V へ)](https://shigeyf.dev/posts/enable-secure-boot-in-ubuntu-vm/../migrate-ubuntu-vm-from-vmware-to-hyper-v/)
で説明した以下の移行手順の ステップ 4 について説明します。

1. VMDK 形式の仮想ディスクを VHD/VHDX 形式への変換
2. 新しい仮想マシンを作成 (変換した仮想ディスクをアタッチする)
3. open-vm-tools のアンインストール
4. (オプション) 第2世代 Hyper-V 仮想マシン用の仮想ディスクへ変換
5. (オプション) **Secure Boot の有効化**
6. Hyper-V 統合サービスのインストール

## セキュアブートの有効化

第 2 世代 Hyper-V 仮想マシンの Ubuntu Linux でセキュアブートを有効にするには、
セキュアブートに対応したカーネルと Grub ブートローダーをインストールする必要があります。

EFIブート対応済みの仮想マシンで起動して、以下の手順を実行します。

### 1) Grub EFI パッケージの取得

以下のコマンドを実行し、Grub EFI パッケージをネットワーク経由でダウンロードしインストールします。

VMware 仮想マシンから移行した場合、ネットワーク接続が可能となるように構成変更するのを忘れないでください。

```bash
sudo apt update
sudo apt install grub-efi-amd64 grub-efi-amd64-signed shim-signed -y
```

### 2) Grub EFI のインストール

~~以下のコマンドを実行し、起動ディスクに Grub EFI をインストールします。~~

**[更新:2023/03/25]**

Grub EFI パッケージのインストーラーにより、
自動的に Grub ブートローダーの更新が実行されるため、以下のコマンドの実行は不要です。

```bash
sudo grub-install --target=x86_64-efi --uefi-secure-boot /dev/sda
sudo grub-install --recheck --uefi-secure-boot /dev/sda
sudo update-grub2
```

### 3) セキュアブートの有効化

セキュアブート対応の Grub EFI ブートローダーのインストールが完了したら、
ライブサーバーをシャットダウンして、仮想マシンの設定を変更します。

仮想マシンの設定から、**[セキュリティ]** -> **[セキュアブートを有効にする]**　のチェックボックスを有効にし、
テンプレートに **[Microsoft UEFI 証明機関]** を選択します。

また、仮想マシンの設定の**[ファームウェア]**の項目で
`grubx64.efi` の代わりに `shimx64.efi` ファイルがブートローダーとして設定されていることを確認します。

### 正常に起動しない場合

`bad shim signature` というメッセージが表示される場合、kernel が最新でないケースが考えられます。

以下のコマンドを実行して、kernel を含む更新を最新の状態にアップグレードすると正常に起動するでしょう。

```bash
apt upgrade -y
```

## セキュアブートが有効になっているかどうかの確認方法

以下のコマンドを実行して、セキュアブートが有効になっているかどうかを確認できます。

```bash
sudo dmesg | grep secureboot
```

"Secure boot enabled" というログが表示されていれば、セキュアブートが有効になっています。

## 最後に

この記事では、第 2 世代の Hyper-V 仮想マシンで Ubuntu Linux のセキュアブートを有効にする方法を説明しました。

Ubuntu Linux 上のサービスでセキュアブートを有効にすると、署名のないドライバーなどを使うことができなくなります。
セキュアな環境を構築できる一方で、セキュリティの考慮がないドライバーなどの利用の際に思わぬ問題に遭遇する場合もあります。
その際には、セキュアブートを無効にして動作を確認することで、問題の切り分けができます。
Protecting real-time GPU kernels on integrated CPU-GPU SoC platforms

https://ieeexplore.ieee.org/document/7939030

https://arxiv.org/abs/1712.08738

### 著者は素人のお知らせ
著者はこの分野の知見を広めてみようかなぁ~くらいの気持ちの人です。普通にメモです。

記事内で出てくるカーネルとはGPUで実行するプログラムのこと。

### まとめ
CPUとGPUが合わさったプラットフォームでは帯域干渉が少ない影響が与える。本論文では効率的にCPUタスクをスケジューリングする方法を提案している。

### Jetsonプラットフォームで起こる問題
JetsonのSoCのようなGPUとCPUがメインメモリを共有しているシステムではCPUでメモリ集中型タスクを実行するとGPU側に大きな影響を与えGPU性能が３分の1くらいになる。

### BWLOCK++概要
BWLOCK++とはCPUのタスクからGPUカーネルを保護するためのソフトウェアフレームワークである。CPUタスクをスロットリング(性能抑制)してGPUタスクを保護する。そこでスロットリングが考慮されたCPUスケジューリングアルゴリズム (= TFS)が提案されている。具体的には以下の内容を実行している。


重要なGPUタスクが実行されている間はメモリ集中型タスクよりCPU集中型タスクを優先する。
よってメモリ集中型CPUタスク存在する中で帯域幅集中型GPUが性能を維持できることができる。CPU側のタスクのスループット損失も大幅に抑えられている。


**用語の定義**
- *メモリ集中型CPUタスク*
    - CPUで実行されメモリ帯域を多く占有するタスク。
- *CPU集中型タスク*
    - CPUの計算が多く占めるタスク。メモリへの負荷は低い
- *帯域幅集中型GPUタスク*
    - GPUで実行されメモリ帯域を多く必要とするタスク。

GPUはCUDA APIを通じて使用されその使われ方は典型的で予測可能であるためCUDA APIの呼び出しをトリガーにBWLOCK++が呼び出されるようにする。ただしソースには手を加えるのことは良くないとのことで動的リンカーとかを経由してバイナリに直接送り込む。

`cudaMalloc` -> `cudaMemcpy` -> `kernel<<<...>>>>` -> のような感じ

以下からBWLOCK++は構成される
1. CUDA APIの実行具合を検出するダイナミックランタイムライブラリ。(ダイナミックリンカーレベルでプログラムバイナリに自動的にインストルメンテーションされる。
2. CPUコアごとのバンド幅レギュレータ
3. スロットルフェアスケジューラ

重要なGPUタスクが実行されている間は、CPUコアごとに単位時間あたりのメモリ転送量予算(クォータ)が割り当てられている。クォータを使い切ったコアはスロットルされる。そのためGPUタスクが実行中の間はCPU集中タスクを優先的に割り当てるようにスケジューリングする。
規制時間ごことに動作する(論文では1ms)突発的な負荷にも対応できる。また長期間にわたる飢餓を防ぐ。


### BWLOCK++実装
プログラマーの介入が必要としないアプローチが支持されている。
Linuxのシステムコールを作っている。


### note

LinuxのCFSスケジューラを使った。しかし副作用があるっぽい。

Armにもちゃんとあるのね(当たり前) L2D CACHE REFILL
Ruby：「Procオブジェクト」「シンボル」について

# Procオブジェクト
Procオブジェクトは、Rubyのオブジェクトの一種で、ブロックをオブジェクト化したものです。ブロックは、一連のコードを囲んで、それをメソッドに渡すために使用されます。しかし、ブロックは通常のオブジェクトではありません。Procオブジェクトを使うことで、ブロックを通常のオブジェクトとして扱い、変数に代入したり、メソッドの引数として渡すことができます。
```ruby
square = Proc.new { |x| x * x }
puts square.call(5) # => 25
```

# シンボル
シンボルは、Rubyのオブジェクトの一種で、イミュータブル（変更不可）な文字列のようなものです。シンボルは、先頭にコロン : を付けることで表現されます。シンボルは、メモリ効率が良く、同じ名前のシンボルは同じオブジェクトとして扱われるため、比較やハッシュのキーとして使う際に高速です。
```ruby
person = {
  :name => "Alice",
  :age => 30,
  :city => "New York"
}

puts person[:name] # => "Alice"
puts person[:age]  # => 30
```

## シンボルと文字列の違い
`string1` と `string2` は同じ内容の文字列ですが、異なるオブジェクトです。一方、`symbol1` と `symbol2` は同じ名前のシンボルで、同じオブジェクトです。これにより、シンボルはメモリ効率が良く、比較が高速になります。
```ruby
string1 = "apple"
string2 = "apple"

puts string1 == string2 # => true
puts string1.object_id == string2.object_id # => false

symbol1 = :apple
symbol2 = :apple

puts symbol1 == symbol2 # => true
puts symbol1.object_id == symbol2.object_id # => true
```
【Git】コミットメッセージのテンプレートを設定する方法

## テンプレートのファイルを作成

ファイルを作成しテンプレートを記述します。  

ファイル名やパスはどのようなものでも大丈夫です。  

今回は`~/.gitmessage.txt`を作成します。  

```zsh
touch ~/.gitmessage.txt
```

`~/.gitmessage.txt`以下のように記述します。  

```txt
subject line

what happened

[ticket: X]
```

## Gitの設定を変更する

テンプレートファイルを作成したら以下のコマンドを実行してGitの設定を変更します。  

```zsh
git config --global commit.template ~/.gitmessage.txt
```

上記を実行すると`~/.gitconfig`または`~/.config/git/config`に以下が追記されます。  

```conf
[commit]
  template = /Users/user_name/.gitmessage.txt
```

なおリポジトリごとに設定する場合には以下のコマンドを実行します。  

```zsh
git config --local commit.template ~/.gitmessage.txt
```

## `git commit`する

上記の設定をしてから`git commit`すると以下のように`~/.gitmessage.txt`の記述が
`.git/COMMIT_EDITMSG`に表示されます。  

```COMMIT_EDITMSG
subject line

what happened

[ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch main
# Changes to be committed:
#	modified:   sample/sample.txt

```
M1 Macユーザー必見！Docker利用時の注意点まとめ

# はじめに
M1 Macを使っていると、たまに「あれ、Dockerファイルを作成する時どこにplatformを定義するんだっけ？？」とわからなくなることがあるので、忘れないようにこちらにまとめておきます。

今回はイメージごとにどのplatformを選択できるのか、Dockerファイルの指定方法、docker-composeを利用する場合の指定方法について記載します。

# Platformの選択

ベースのイメージは基本DockerHubから取得される方が多いと思いますので、DockerHubを利用することを前提に話を進めます。
DockerHubでは、イメージが対応するアーキテクチャがに公開されています。
例えば[python](https://hub.docker.com/_/python)のイメージだと、以下のようにサポートされているアーキテクチャ一覧が確認できます。

![python.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271464/d6822835-eb01-169b-ca6c-2ccbf8f2130c.png)


ARM64やx86-64とあります。こちらを見ると対応するアーキテクチャがわかるので、
これを見てどのアーキテクチャが利用できるか事前に確認しておく必要があります。

# Dockerfileでplatformを指定する
利用できるアーキテクチャがわかったら、実際にDockerファイルにplatformを指定します。

`FROM`のinstructionに`--platform`オプションをつけてアーキテクチャを指定することができます。

```Dockerfile
FROM --platform=linux/amd64 python:3.9.16

WORKDIR /app
# x86_64
```

CLIを利用する場合も同様です。

```bash
docker run -it --platform=linux/amd64 python:3.9.16 

# x86_64
```

# Docker Composeでplatformを指定する
DockerComposeの場合は、`compose.yml`に以下のように指定します。

```yml
version: '3'
services:
  mysql:
    image: python:3.9.16
    platform: linux/amd64
    working_dir: /app
    ports:
      - 5000:5000
 ```

# さいごに
今回はAppleSiliconのチップ(M1, M2)が搭載されたMacでDockerを利用する際にplatformの指定方法について紹介しました。
アーキテクチャは意外と忘れやすいので、利用前にサポートするアーキテクチャを調べておくことが重要かと思います。

# 参考
- https://developer.a-blogcms.jp/blog/custom/docker-arm64.html
- https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0167
npm creae vite@latestで作成したプロジェクトがVSCodeでエラーになる

# はじめに

最近よくViteでプロジェクトを作るのですが、作ったときに突然VSCodeでエラーがでるようになったのでまとめます
根本的な解決はしていないので回避方法を紹介します

# 問題

以下のコマンドでいつもどおりViteでReact環境を作りました

```bash
$ npm create vite@latest
# ReactとTypeScriptの環境を作成
```

VSCodeで開くと以下のようにエラーが出ます

`tsconfig.json`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/724051da-d190-e151-a778-70d0f46d7f4c.png)

`main.ts`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/54393a3b-c102-86fd-52a9-d796f4b9feb5.png)

いままででたことなかったのになぜ、、、

# 解決方法

最近Viteの新しいバージョンがでていたのでそれがいままでと違う挙動になった原因でした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/4e81b8fa-614e-581d-a089-94dcd6010a72.png)
https://www.npmjs.com/package/create-vite

この時点では最新の`4.3.0`が入っているようだったので1ヶ月前に使っていた`4.2.0`でいれたところVSCodeでエラーがなくなりました

```bash
$ npm create vite@4.2.0
```

# おわりに

今後を考えるとこの問題をなんとか解決しないとですが、いまは早くプロジェクトを作りたかったので回避することにしました

# 参考

https://www.npmjs.com/package/create-vite
Vue.jsのTypeScript化

## 手順
ツール等は特に使わず、下記手順で実施。

https://typescript-jp.gitbook.io/deep-dive/type-system/migrating


>- tsconfig.jsonを追加する
>- 新しいコードはTypeScriptで記述し、できるだけanyを使わないようにする
>- 古いコードに戻り、型アノテーションを追加し、バグを修正する
>- ソースコードの拡張子を .jsから.tsに変更する。any型を使ってエラーを抑制する

Vue3への移行も同時に実施し、[CompositionAPI](https://ja.vuejs.org/guide/typescript/composition-api.html)への書き換えも行っていたので、setupもついでに付与。
あとはとにかくany使わず型付け。型を追い続ける。
```test.vue
<script setup lang="ts">
</script>
```


### 困りポイント
```
console.log(window.testFunction)

=> Property 'testFunction' does not exist on type 'Window & typeof globalThis'.
```
別ファイルのjsでwindow直下に生やしたfunctionが、jsでは参照できるがtsだと見つからないと言われる。

### 解決
```window.ts
interface Window {
  function testFunction(s: string): string;
}
declare var window: Window
```
上記で記述で参照可能になる。ただambient宣言をあまり使いたくないので微妙。
実際の対応は、window直下に生やす意味がなさそうだったので、vueファイルの中に関数を移植した。
App02　確認画面

# 概要
確認ボタンの作成
## 画面

<img width="300" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964715/16b25fe4-657c-925a-ca8b-ba946a17b4fb.png">

## 動作確認
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">app02 確認画面 <a href="https://t.co/WKkNMIo2RB">pic.twitter.com/WKkNMIo2RB</a></p>&mdash; いまむら　たくま (@Imamuuu5) <a href="https://twitter.com/Imamuuu5/status/1650491245524041729?ref_src=twsrc%5Etfw">April 24, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# ソースコード
## カラー
###  colors.xml　

```java 
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#008577</color>
    <color name="colorPrimaryDark">#00574B</color>
    <color name="colorAccent">#D81B60</color>
</resources>
```

# レイアウト
## activity_main.xml
```java
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<TextView
    android:id="@+id/text1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="確認待ち" />

<Button
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="確認中" />

<Button
    android:id="@+id/btn2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="確認しました" />

    </LinearLayout>

```

# java
## MainActivity.java

```java

package com.example.app02;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {   // Activity(画面）のクラスを継承

    private TextView text1;     // TextViewの変数を用意
    private Button btn1;        // Buttonの変数を用意
    private Button btn2;        // Buttonの変数を用意

    @Override   // オーバーライドアノテーション 親クラスのメソッドを上書きしてメソッドを定義するという印
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);         // 親クラス（AppCompatActivity）で定義されたonCreate()を実行
        setContentView(R.layout.activity_main);     // 画面をactivity_mainに設定
        text1 = findViewById(R.id.text1);           // 画面からtext1というIDのViewを探してtext1に代入
        btn1 = findViewById(R.id.btn1);             // 画面からbtn1というIDのViewを探してbtn1に代入
        btn2 = findViewById(R.id.btn2);             // 画面からbtn2というIDのViewを探してbtn2に代入

        btn1.setOnClickListener(new View.OnClickListener() {    // btn1をクリックしたときの処理を設定
            @Override
            public void onClick(View view) {
                text1.setText("確認中");   // text1のテキストを「確認中」に変更
            }
        });

        btn2.setOnClickListener(new View.OnClickListener() {    // btn2をクリックしたときの処理を設定
            @Override
            public void onClick(View view) {
                text1.setText("確認しました");    // text1のテキストを「確認しました」に変更
            }
        });
    }
}

```
大学を留年中退してもなんだかんだ普通にエンジニアしてる話

# はじめに

この4月からエンジニアとして4年目になりました。
タイトルの通り、**大学を2回留年した上に退学**しても、なんだかんだ普通の社会人として生きていけるということを昔退学したての自分や(かなりレアだと思いますが)昔の自分のような人がいれば教えてあげたいなと思い記事にしました。
さらに、私はすでに**2回転職**をしているのでそのあたりもお話しできればと思います。

# 大学中退から1社目

大学を留年して退学理由は割愛します。(あまりいい話はできないので・・・)

地方国公立大学に通っていたのでそのままその地域で就職活動をし、たまたま内定が出た業務システムを開発、販売している小さな会社に就職しました。
中小企業のため非常に緩く、その年の夏休み明けからアルバイトとして働き始めて中退するとなった時も「別にいいよ～」という感じで許していただき翌年の4月から正社員として働き始めました。

大手とは違いまともな研修がないため、技術本を数冊渡されて自分で業務に必要な知識を身に着けて、4月からはコーダーとして実際に開発をしていました。
大学がCS関係ではなく業務の内容やエンジニアのことが知らないことだらけで非常に苦労しました。(エンジニアは1年目が一番きついとは言われてますが)

このころの私は、非常に学歴コンプといいますか、**劣等感を感じていた**のでその差を埋めるべく少しでも成長しようと無我夢中でした。

* 少しでも経験を積むべく1秒でも早くコーディングを終わらす。(ただしバグ大量発生)
* 技術本や雑誌をひたすら読む。
* 基本情報の勉強をする。(当日寝坊)
* AWS認定を受ける。(CLF合格)

上記のことを実行しました。

このころに読んだ本で一番心に残ってるのは「オライリー リーダブルコード」です。
技術的負債をためないコードの書き方やコメントの重要性など今のコーディングでも使っている知識などがあり非常に勉強になりました。

基本情報の勉強もエンジニアとしての知識を体系的に学べましたしAWS認定もAWSだけでなくネットワークの知識の理解も深まるのですべてが役立っています。

1年ほど公私ともに学んでいると自分が挑戦してみたい分野というものが生まれてきました。

拾っていただいた恩はありましたが転職を決意し入社して1年半たったあたりで退職し次の会社へ行くことにしました。

# 転職活動と2社目

私自身大学中退と経歴が汚れているのでそもそも書類が通るかなど不安でしたが、転職活動は特に問題なく進みとんとん拍子で内定を頂きました。

私の持っている技術スタックが相手方が求めている人材と非常にマッチしていたので、ここの転職活動は非常に運があったと思っています。

私のやりたい分野というのがクラウド関係で、クラウド技術を使ったシステムに携わりたいと思い2社目は、WEB系で映像関係のシステムを扱っている会社に転職しました。

ここでも1年目でやっていたことは継続して行い自己研磨に励みました。

* 早さも大事だが保守性の高いコードを書くことを意識
* 技術本や雑誌をひたすら読む。
* 応用情報の勉強をする。(挑戦中)
* AWS認定を受ける。(SAA合格)

このころには会社の上司の方や仲間から非常に評価されるようになり、難易度の高い仕事を振られたりリーダー職も任されたりと様々な経験をさせてもらいました。

このころには社会人なりたての頃に感じていた**劣等感**はなくなり自信がついてきました。

2社目で非常にいい経験をさせてもらい成長したと感じますが、さらにレベルの高い環境で新規サービスの立ち上げに携わってい見たいと思い再び転職しようと決意しました。

# 直近の転職活動

新卒の時含めて今までで一番慎重に行った転職活動でした。

自分がどのような仕事をしたいのか、会社に対してどのような待遇を望むか、環境はどうなのかなど総合的に自己分析や企業分析を行いました。

エージェントも利用して様々な方向から転職活動を行いました。

自分の技術や経験に自信を持っていたといえ自分の経歴が汚れているのに多少後ろめたさがありましたが、この時に受けた企業がメガベンチャーや大手企業も含まれており、いくつかの企業から内定もいただきもはや学歴などは関係ないのだなと感じ少なくとも社会人になってやってきた努力は無駄ではなかったと感じました。

結果、自分が納得できる会社とポジションに転職できて現在その会社で働いております。

前職の最後の方は自信過剰すぎて謎の全能感があっただけに今現在逆異世界転生でわからないことだらけになり、きつさを感じますがそれ以上に挑戦者としてたのしさを感じています。

# 結局何が言いたかったか

大学2留中退でも、日々努力していればそれなりに良いエンジニア人生送れるということを伝えたかったです。

おそらくエンジニアだけには限らないと思いますが、精神さえ元気で働くことができるなら人生何とかなると考えています。

変に学歴コンプや劣等感を抱えている人がいれば、そう思っているくらいならそれを覆すくらいの知識と経験で覆せるようお互い頑張っていきましょう。

# 今後どうしようか

今回それなりに有名な企業に入り少しだけ燃え尽き症候群みたいなものを感じていました。

なのでこのように記事にして振り返ってもう一度頑張ろうというモチベにしようと考えました。

あとSNSやキータの他の記事をみたりすると自分より若いのにつよつよなエンジニアが多くて少しだけ嫉妬してしまいますが逆に負けたくないとモチベーションが上がります。

今後は今まで通りインプットしつつ、このようにアウトプットも増やしていきたいなと思います。

あとは、IPAの試験の高度取りたいとかAWS認定12冠したいとかやりたいことはたくさんあります。

一つ一つ自分のペースで成長していきたいと思います。

ここまで読んでいただきありがとうございました。
【Rails】Rails6でTurbo Framesを導入する方法

## はじめに
Turbo Framesとは、ページを部分的に更新したり、遅延読み込みができるようになったりするAjax通信のような機能です。
Rails7からデフォルトでインストールされるHotwaireというフレームワークの機能の一部です。

## 導入
Gemfileに`turbo-rails`というgemを追加します。
```ruby:Gemfile
gem 'turbo-rails'
```
```
$ bundle install
```
インストールします。
```
$ bin/rails turbo:install
```
以下を`app/javascript/application.js`ファイルに追加します。
```javascript:app/javascript/application.js
import "@hotwired/turbo-rails"
```
以上でTurbo Framesを利用できるようになりました！

## 参考
https://github.com/hotwired/turbo-rails

https://zenn.dev/takeyuwebinc/articles/4bbb3df6ef6344
Aliasディレクティブで設定したパスだけService Temporarily Unavailableになる

ErogameScapeはスマホ用の画面があります。
具体的には/sp/にアクセスするとスマホ用の画面が表示されます。

ユーザーさんから、数日前からスマホ用のサイトにアクセスするとService Temporarily Unavailableになる、と連絡を頂きました。
PC用のサイトはOKとのことです。

PC用のサイトはスマホ用のサイトと同じサーバー(Apache)で動かしています。
ソフトのVerは以下の通りです。
```
# httpd -v
Server version: Apache/2.4.37 (AlmaLinux)
Server built:   Apr  6 2023 13:28:53
# php -v
PHP 8.2.5 (cli) (built: Apr 11 2023 16:16:23) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.2.5, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.5, Copyright (c), by Zend Technologies
# php-fpm -v
PHP 8.2.5 (fpm-fcgi) (built: Apr 11 2023 16:16:23)
Copyright (c) The PHP Group
Zend Engine v4.2.5, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.5, Copyright (c), by Zend Technologies

```
PC用のサイトは歴史的な理由から
```conf
<IfModule mod_userdir.c>
    UserDir public_html
</IfModule>
```
で設定したディレクトリで動いており、スマホ用のサイトは
```conf
Alias /sp /home/ap2/sp/sp
```
で設定したディレクトリで動いています。

Service Temporarily Unavailableになるということは、PHPが応答を返していないからだと推測しました。
まず、httpdを再起動しましたが状況かわらず。
次に、php-fpmを再起動して回復しました。

以下調査結果です。
そういえばここ数日Logwatchのメールに見慣れないWARINGがあることを思い出しました。
```
--------------------- Kernel Begin ------------------------
 WARNING:  Segmentation Faults in these executables
    php-fpm :  1437 Time(s)

 1437 Time(s): Code: 10 48 63 d2 8b 3c 97 89 78 0c 49 8b 46 10 89 0c 90 41 83 46 1c 01 f6 46 1c 08 74 23 49 8b 47 18 80 78 18 00 74 19 48 8b 46 08 <f6> 40 04 20 74 0f 8b 00 48 8b 95 e0 01 00 00 48 89 34 02 66 90 49

---------------------- Kernel End -------------------------
```
php-fpmがセグフォしております…
`/var/log/messages`を確認しました。
以下のようなメッセージが多数記録されていました。
```
Apr 19 12:53:31 sakura kernel: php-fpm[3489566]: segfault at fffffffc00000014 ip 00007fbe6df3733b sp 00007ffe316e1940 error
5 in opcache.so[7fbe6df02000+e3000]
Apr 19 12:53:31 sakura kernel: Code: 10 48 63 d2 8b 3c 97 89 78 0c 49 8b 46 10 89 0c 90 41 83 46 1c 01 f6 46 1c 08 74 23 49
8b 47 18 80 78 18 00 74 19 48 8b 46 08 <f6> 40 04 20 74 0f 8b 00 48 8b 95 e0 01 00 00 48 89 34 02 66 90 49
```
一番最初に上記メッセージが出たところまでたどったところ`/var/log/messages`に以下の通り出力されていました。
```
Apr 19 12:53:01 sakura kernel: httpd invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0
Apr 19 12:53:01 sakura kernel: CPU: 0 PID: 3488266 Comm: httpd Kdump: loaded Not tainted 4.18.0-372.32.1.el8_6.x86_64 #1
Apr 19 12:53:01 sakura kernel: Hardware name: FUJITSU PRIMERGY RX1330 M3/D3375-B1, BIOS V5.0.0.11 R1.23.0 for D3375-B1x
               04/25/2019
Apr 19 12:53:01 sakura kernel: Call Trace:
Apr 19 12:53:01 sakura kernel: dump_stack+0x41/0x60
Apr 19 12:53:01 sakura kernel: dump_header+0x4a/0x1df
Apr 19 12:53:01 sakura kernel: oom_kill_process.cold.32+0xb/0x10
Apr 19 12:53:01 sakura kernel: out_of_memory+0x1bd/0x4e0
以下略
```
oom-killerが動いています。
ユーザーさんが無限ループする再帰的なSQLを何回も実行してサーバーの負荷が著しくあがっているタイミングでした。
無限ループする再帰的なSQLの影響でメモリを食いつぶしてoom-killerが動いたのだと思います。
そして理由はわからないですが、このときからphp-fpmのsegfaultがでるようになりました。

不思議なのは/sp/配下のphpにアクセスしたときだけ(おそらく)php-fpmがセグフォして落ちていたと思われる…ということです。
でも、経験上、何かが壊れると自分の想像しない動作をすることがほとんどでしたので…、そういう壊れ方(今回は何かが物理的に壊れたわけではないですが…)もあるんだな、と納得することにしました。

次からはKernelのWARNINGをスルーしないようにいたします。
Azure Container RegistryからAzure Container Instancesへデプロイする

## 目的
業務でAzure Container Instances使う可能性が出てきたため
その際の調査結果を書き留めておくのが目的です

## 概要
[前回](https://qiita.com/sinden30610/items/6c8430bfa3e8b945dd1b)の続き
Azure Container RegistryからAzure Container Instancesへデプロイするとこまでを記載しています

## 実施環境
- Windows 11
- WSL2
- Docker DeskTop 4.18.0 (104112)

## 必要なもの
- Azureアカウント
- Azure CLI バージョン 2.4 以降
- Windowsターミナル

## 手順
### 1. レジストリ資格情報を取得
```
az acr show --name sample20230422 --query loginServer
```

### 2. Azure Container Instancesにデプロイする
※--registry-usernameと--registry-passwordは
コンテナレジストリのアクセスキーの画面で管理者ユーザーを有効にします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/feee2593-f247-a8ae-5f6b-41950af3f633.png)

```
az container create --resource-group sample20230422 --name sample20230422 --image sample20230422.azurecr.io/sample20230422-flask_job:v1 --cpu 1 --memory 1 --registry-login-server sample20230422.azurecr.io --registry-username ユーザ名 --registry-password パスワード
```

### 3. デプロイの進行状況を確認する
```
az container show --resource-group sample20230422 --name sample20230422 --query instanceView.state
```

以下のようになったらOKです
```
"Running"
```

### 4.ログを表示する
```
az container logs --resource-group sample20230422 --name sample20230422
```

以下のような表示が帰ってくればOKです
```
hoge
```

## 参考サイト
https://learn.microsoft.com/ja-jp/azure/container-instances/container-instances-tutorial-deploy-app
goのtestfixtureで配列を登録する方法



## はじめに

業務でGOのテストする際に[go-testfixtures](https://github.com/go-testfixtures/testfixtures)ライブラリに大変お世話になっています。このライブラリを使うと、yamlファイルからテスト用DBのデータを簡単に作ることができます。

詳しくはREADME.mdを読んで欲しいのですが、yamlファイルに下記のように書くだけ、DBのデータを追加することが可能です。

```
# comments.yml
- id: 1
  post_id: 1
  content: A comment...
  author_name: John Doe
  author_email: john@doe.com
  created_at: 2020-12-31 23:59:59
  updated_at: 2020-12-31 23:59:59

- id: 2
  post_id: 2
  content: Another comment...
  author_name: John Doe
  author_email: john@doe.com
  created_at: 2020-12-31 23:59:59
  updated_at: 2020-12-31 23:59:59
```


で、今回、DBのスキーマがarray型の時はどうやって書くねん？？となったので、備忘録として残しておきます。

## いきなり結論

- RAWを使う。
- SQLで{}で囲むと配列のリテラル表現となる。下記のようにRAW=とするのことで、rawのSQL文として配列をDBに直接登録できる

yaml
```
- id: 1
  name_array: RAW='{tanaka, suzuki}'
- id: 2
  name_array: RAW='{takahashi, chakuradokuro}'
```


## 余談
- RAWは便利でこれ以外にもめっちゃ使ってます。RAW=pgp_sym_encrypt()やらRAW=NOW()やら、何かと使う機会があるのでぜひ覚えてみてください。
損失関数ってなぁに？

# もくじ
>[損失関数ってなぁに?](#損失関数ってなぁに?) 
[主に使われる損失関数](#主に使われる損失関数)
[まとめ](#まとめ)

# 損失関数ってなぁに?
ズバリ
　
　
　
#### 損失の関数。
　
　
　
　


### (ｏﾟДﾟ)＝◯)`3゜)∵ﾍﾌﾞ
　
　まず損失とは何か？
　G○○gle先生に聞くと「損ない失うこと」と出てきます。ここでは、人間が決めた「正解値」とモデルによって算出された「予測値」とがあり、この差を**損失**と呼びます。
　そして、この損失を求める際に使用される数式のことを損失関数と言います。別名、誤差関数とも言います。
　
　この損失を少なくしていくことを**学習**と言います。


# 主に使われる損失関数
　主に使われる損失関数は３つ

+ 平均二乗誤差(MSE)関数
+ 交差エントロピー(クロスエントロピー)誤差関数
+ バイナリクロスエントロピー誤差関数

### 平均二乗誤差(MSE)関数
```math
 MSE= \frac{1}{n} \sum_{i=1}^{n}( y_i -\hat{y}_i)^2\\
 n=データの総数　i=i番目のデータ　y=正解地　\hat{y}=予測値

```
　こちらが損失関数の中で最もポピュラーな損失関数です。
　計算結果は予測値から正解値を引いたものを2乗し、その総和をデータ数で割ると算出できます。
　イメージとしては、正解値と予測値を直線で結び(ユークリッド距離)、どれくらい離れているかを求めている。



### 交差エントロピー(クロスエントロピー)誤差関数
```math
 cross　entropy= -\sum_{i=1}^{n} y_i \log_e \hat{y}_i\\
 n=データの総数　i=i番目のデータ　y=正解地　\hat{y}=予測値
```
　現在、多くの分類問題の学習に使用されている関数です。
　分類問題の多くでは、結果を離散確立分布として出力するという性質を利用しています。
　クロスエントロピーでは、正解値と予測値の自然対数の値を掛け、それらの値を総和し、その結果に-1を掛けることでで算出できます。

### バイナリクロスエントロピー誤差関数
```math
 binary　cross　entropy = -y\log_e \hat{y} - (1-y)\log_e (1-\hat{y}) \\
y=正解地　\hat{y}=予測値
```
　片方の確率が分かると、もう片方の確率も自動的に求められる(1から求められた確率を引くだけで求められる)性質を利用しています。
　二値分類の場合は、この損失関数を使うことで計算量を抑えることができます。



# まとめ
　あくまで触り程度ですが、損失関数のご紹介でした！
　もっと詳しく知りたい方はそれぞれの名前単体で検索を掛けてみるといいんじゃなかろうか…
記事作成：N&Y
　
　
　
　
　さっきはよくｍ…
(ｏﾟДﾟ)＝◯)`3゜)∵
　↑Y氏　　　↑N氏
コアウェブバイタル(Core Web Vitals)

## コアウェブバイタル（Core Web Vitals）について
コアウェブバイタル(Core Web Vitals)とは、Googleが提案したWebページのパフォーマンスを測定するための指標です
2020年5月にGoogleが発表し、業界標準としての指標が統一されました
2021年6月からGoogleの検索ランキングにコアウェブバイタルが組み込まれました
コアウェブバイタルの評価は以下の3つを指標としています
- Largest Contentful Paint (LCP)：ページの読み込み速度
- First Input Delay (FID)：インタラクティブ性
- Cumulative Layout Shift (CLS)：ページの安定性

### Largest Contentful Paint (LCP)
LCPはユーザーがページがどれだけ速く表示できるかを評価します
良好なLCPは、2.5秒以内とされています

__LCPを改善する方法：__
画像の最適化/CSSおよびJavaScriptの最適化（非同期読み込みの活用）/サーバー応答時間の短縮（キャッシュの最適化やCDNの導入）

### First Input Delay (FID)
FIDはユーザーがページ上の要素（例：ボタンやリンク）に対して最初の操作を行った際に、その処理が実行されるまでの遅延時間を評価します
良好なFIDは、100ミリ秒以内とされています

__FIDを改善する方法：__
JavaScriptの最適化（コードの削減、非同期読み込みの実装、遅延読み込みの導入）/サードパーティスクリプトの最適化（数を減らす、非同期読み込みを行う）

### Cumulative Layout Shift (CLS)
CLSはユーザーが誤った操作を行うリスクがどれだけ高いかを評価しています
良好なCLSは、0.1以下とされています

> CLSスコアは、0から1の範囲で表され、0が完全に安定したページ（要素の予期せぬ移動がない）を意味し、1が最も不安定なページ（要素の大幅な予期せぬ移動がある）を示します
このスコアは、個々の要素のレイアウトシフトスコアの合計で計算されます
レイアウトシフトスコアは、要素が画面上で移動した距離と、その移動の視覚的影響を考慮して計算されます
具体的には、要素が画面の何パーセント移動したか、要素の移動が画面全体の何パーセントの領域に影響を与えたかを掛け合わせることで、その要素のレイアウトシフトスコアが算出されます
0.1以下のCLSスコアは、ウェブページが安定していると見なされ、ユーザーエクスペリエンスに悪影響を及ぼすことはほとんどありません
この閾値は、Googleがウェブページの品質を評価する際に用いるベンチマークです
一般的には、CLSスコアが0.1以下であれば、ユーザーはページ上の要素が予期せず移動することによる不快感や誤操作のリスクをほとんど感じないとされています

__CLSを改善する方法：__
画像や動画要素に寸法（幅と高さ）を指定する/広告やダイナミックコンテンツのスペースを予約する/フォントやスタイルシートの読み込み方法を最適化する（FOITの防止、CSSの最適化）

## まとめ
考慮すべきコアウェブバイタル指標を適切に取り入れたウェブサイト制作によって、ユーザーエクスペリエンスが向上しサイトの品質が高まります
これによりウェブサイトの検索エンジンランキングが上昇し、ユーザー満足度が増加します
さらに、Webページのパフォーマンスが改善され検索ランキングの向上にも繋がります
スマホで写真の撮影地の住所を取得する Pythonista3 スクリプト

## 写真から住所を取得
　以前「Pythonista でiPhoneの写真撮影場所へルート案内」という記事を投稿していました。

https://qiita.com/ynomura/items/950a3a99bdca4666c33a

　自分で行く場合はそれでも良かったのですが、例えばタクシーで行こうとするとGPS情報よりも住所で伝える方が良いですね。
ということで、写真のGPS情報から Google Maps API を使って住所を取得する機能を Pythonista3 で作りました。

## 早速、ソースです。
　
```Python:getAdrsFromPhoto
#!python3
# _*_ coding: utf-8 _*_

import photos
import clipboard
import requests
import json

gm = 'https://maps.googleapis.com/maps/api/geocode/json?language=ja&latlng='
pk = '<YOUR API-KEY>'

p = photos.pick_asset()
pl = p.location
loc = str(pl['latitude']) + ',' + str(pl['longitude'])
url = gm + loc + '&key=' + pk

r = requests.get(url)

adrs = json.loads(r.text)['results'][0]['formatted_address']

print(adrs)
clipboard.set(adrs)

```

&LT;YOUR API-KEY&GT;　のところは、Google Maps API の API Key をセットしてください。
iPhone の設定で Pythonista3 に写真へのフルアクセスを許可しておきます。

実行すると写真を選択する画面になりますので、対象の写真を選択します。
コンソールに住所が表示されると同時に、クリップボードにもセットされていますので、任意のアプリにペーストして利用します。

## ご意見、ご指摘を歓迎
　お気づきの点がありましたら、コメントをお願いします。
Javaで電卓を実装してみた

# 概要
今日はJavaの勉強ということで、電卓を作ってみました。以下のページを参考にしました。
https://www.javadrive.jp/start/sample1/index1.html

# ソースコード
上記のページは式を表示するだけだったので、計算もさせて結果を表示させてみました。
ソースコードは以下の通りです。
```dentaku2.java
class dentaku2{
  public static void main(String args[]){
    int val1 = 0;  /* 最初の数字 */
    int val2 = 0;  /* 次の数字 */
    String ope;    /* 演算子 */

    if (args.length != 3){
      System.out.println("Usage : java dentaku 数値 演算子 数値");
      System.out.println("演算子は kake waru tasu hiku の4つです");
      System.exit(0);  /* プログラムを終了する */
    }

    val1 = Integer.parseInt(args[0]);
    val2 = Integer.parseInt(args[2]);
    ope = args[1];

    System.out.println("入力された式は " + val1 + " " + ope + " " + val2 + " です");
    if(ope.equals("kake")==true) System.out.println("計算結果は "+(val1*val2));
    if(ope.equals("waru")==true) System.out.println("計算結果は "+(val1/val2));
    if(ope.equals("tasu")==true) System.out.println("計算結果は "+(val1+val2));
    if(ope.equals("hiku")==true) System.out.println("計算結果は "+(val1-val2));
  }
}
```

# 実行結果
コンパイルします。
```
$ javac dentaku2.java
```

実行します。
```
$ java dentaku2 2 kake 3
入力された式は 2 kake 3 です
計算結果は 6
$ java dentaku2 2 waru 3
入力された式は 2 waru 3 です
計算結果は 0
$ java dentaku2 2 tasu 3
入力された式は 2 tasu 3 です
計算結果は 5
$ java dentaku2 2 hiku 3
入力された式は 2 hiku 3 です
計算結果は -1
```

何かの役に立てばと。
Webpackerのビルド高速化

いくつか試したことまとめ。各詳細は公式のドキュメント読もう。

# SplitChunks有効化
Webpacker4で使える追加機能。
宣言は`config/webpack/environment.js`に1行追記するだけ。

```config/webpack/environment.js
environment.splitChunks()
```

呼び出し用のタグを`***_pack_tag`から`***_packs_with_chunks_tag`変更。
```app/views/layouts/test.slim
= javascript_packs_with_chunks_tag 'test'
= stylesheet_packs_with_chunks_tag 'test'
```

この状態でコンパイルすれば、SplitChunksで生成したファイルを読み込んでくれる。
コンパイル時`.chunk.js`が生成されていればOK。
```
  js/*****.chunk.js   4.23 MiB
```

# babel-loaderキャッシュ有効化
設定にcacheDirectoryオプションを追加。
```config/webpack/loaders/babel.js
module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          cacheDirectory: true //これ
        }
      }
    }
  ]
}
```

`/node_modules/.cache`配下にキャッシュが生成されていればOK。
```bash
$ ls -l node_modules/.cache/
drwxr-xr-x - test test 2023-04-21 17:28 babel-loader
```

# HardSourceWebpackPlugin導入
キャッシュを生成して、2回目以降のビルドを高速化してくれるらしい。

インストールして
```
　yarn add -D hard-source-webpack-plugin
```

設定ファイルにプラグインを追加する。
```config/webpack/development.js
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

environment.plugins.prepend('HardSourceWebpackPlugin', new HardSourceWebpackPlugin());
```

こちらも`/node_modules/.cache`配下にキャッシュが生成されていればOK。
```bash
$ ls -l node_modules/.cache/
drwxr-xr-x - test test 2023-04-21 17:28 hard-source
```

# SourceMap無効化
SourceMapは、コンパイル前とコンパイル後の対応関係を記したファイルなので、
デバッグとかで使っていたらこの対応はしない方が良いかも。

設定ファイルの`devtool`を弄るだけ。
```config/webpack/development.js
environment.config.merge({
  devtool: 'none', //'inline-source-map'でSourceMap出力
});
```

コンパイル時、SourceMap(.map.js)が出力されなくなっていればOK。

# ビルド速度比較
| | 1回目 | 2回目 | 3回目 | 4回目 | 5回目 |
|-| ----- | ----- | ----- | ----- | ----- | 
| **適用前** | 93872ms | 17328ms | 13502ms | 12905ms | 11054ms |
| **適用後** | 87756ms  | 17912ms | 8260ms | 9284ms | 6872ms |

2回目以降でキャッシュが上手いこと使えていると、早くなっているっぽい。
適当に小さい処理やログ出力挟んだ程度の変更なので、規模次第でどうなるまではまだ分からず。
【Swift】zip関数をはじめて使った

# はじめに
zip関数は配列や辞書などをタプルにしてくれる機能らしいです。

# 例
2つの配列をタプルの配列に変換しています。
```swift
let alphabets = ["A", "B", "C"]
let index = [1, 2, 3]

let zipped = Array(zip(alphabets, index))

print(zipped)
// [(A, 1), (B, 2), (C, 3)]
```

では、配列の中の個数が違う場合はどのようになるでしょうか？

```swift
let alphabets = ["A", "B", "C"]
let index = [1, 2]

let zipped = Array(zip(alphabets, index))

print(zipped)
// [(A, 1), (B, 2)]
```

少ないほうに合わせてタプルが生成されました。

# おわり
難しいと思っていましたが、意外と単純なものでした。
Selenium Webdriver での Role 指定によるパーツの取得方法について

## はじめに
以下の理由から ARIA 属性をロケーターに使うことがより良いとされています 

- ソフトウェアの使用方法にテストが沿っていると信頼性が高まる
- 自然と正しくroleやラベルを設定する力学もはたらく = アクセシブルになる

## 結論

Selenium Webdriver では他のテストツールのように簡潔に実装はできない、かつ取れない要素もある。

以下、他のツールの実装例。

ex. [Playwright  get_by_role](https://playwright.dev/python/docs/locators#locate-by-role)

```typescript
page.get_by_role("button", name="ボタンです2")
```
```html
<div role="button">
	<p>ボタンです1</p>
</div>
<button>
	<p>ボタンです2</p>
</button>
```
いい感じに「ボタンです2」の要素が指定できる。（動作未確認）

## Selenium Webdriver で TRY

[Ruby の Selenium Webdriver ライブラリのfind_element メソッド](https://www.selenium.dev/selenium/docs/api/rb/Selenium/WebDriver/SearchContext.html#find_element-instance_method)では以下の種類の探索方法をサポートしている。

```
{
  class: 'class name',
  class_name: 'class name',
  css: 'css selector',
  id: 'id',
  link: 'link text',
  link_text: 'link text',
  name: 'name',
  partial_link_text: 'partial link text',
  relative: 'relative',
  tag_name: 'tag name',
  xpath: 'xpath'
}.freeze
```



Role はサポートされていないので、上記のいずれかで表現する必要がある。

以下のHTML を `xpath` で探索してみる。

```
<div role="button">
	<p>ボタンです1</p>
</div>
<button>
	<p>ボタンです2</p>
</button>
```

- `//*[@role="button"]`  
  - 「ボタンです1」上のdiv のみ探索される
  - 明示的にrole を定義していないと探索され**ない**
- `//*[@role="button"]//*[text()="ボタンです1"]` 
  - 「ボタンです1」の p タグが探索される
  - 指定のロールのタグの下のテキストノード（ ARIA の Name ）に当たるものを擬似的に探索することはできる


## 結論

Playwright などのテスティングフレームワークほど簡潔に実装はできないかつ、取れない要素もありました :cry: 

他にやり方をご存じの方いましたらコメントください。
Alpine 3.17のNodeコンテナをLambdaで動かす

タイトルに書いたように、Alpine 3.17+NodeのコンテナをLambdaで動かすことに成功しました。

## TL; DR

* Alpine 3.17では`libexecinfo`が消えている
* 代わりに`libdw`（`elfutils`）を使うことができる
* `libbfd`、`libdwarf`ではうまくいかない

## Nodeコンテナの意味

Lambdaで、Node.jsにはデフォルトのサポートがあるので、別にコンテナを立てずともコードを書いて動かすことが可能です。

ただ、ネイティブの実行ファイルと絡めて動作させたいような場合など、コンテナ内でNode.jsを動かすという構成も意味のあるものとなりえます。

## Lambda用ライブラリと問題

Node用のLambdaランタイムは[aws-lambda-ric](https://www.npmjs.com/package/aws-lambda-ric)として公開されていますが、これはネイティブコードのコンパイルを伴います。

Alpine 3.16であれば、`libexecinfo-dev`というライブラリを追加すればビルド処理が可能です。ところが、Alpine 3.17では標準のリポジトリから`libexecinfo-dev`がなくなっていて、そのままビルドすることができない状況です。

## さらに調べて他の選択肢へ

さらに調べると、aws-lambda-ricのネイティブコードは、[aws-lambda-cpp](https://github.com/awslabs/aws-lambda-cpp)にパッチを当てたものだということが判明しました。そして[ソースコード](https://github.com/awslabs/aws-lambda-cpp/blob/4668e1a8939d34992fe4e8b49e60e646246adb69/src/backward.h#L136)を見てみると、`libexecinfo`だけでなく、4通りのライブラリパターンが想定されていました。

* `libdw`
* `libbfd`
* `libdwarf`
* `libexecinfo`

そして、4通り全てを試してみたのですが、正常に動作するパターンが1つだけ存在しました。

* `libexecinfo`はAlpine 3.17に存在せず
* `libdwarf`はインストールしてもビルドプロセスで存在が認識されず失敗
* `libbfd`（`binutils-dev`パッケージにあり）は、aws-lambda-ric添付のaws-lambda-cppが古いバージョンで、`libbfd`サイドの変遷についていっていないという[不具合が残ったまま](https://github.com/awslabs/aws-lambda-cpp/issues/93)で失敗
* `libdw`（`elfutils-dev`パッケージにあり）…**成功**

ということで、ビルド環境に`elfutils-dev`、実行環境に`elfutils`を入れておけば無事に解決しました。
ChatGPTセミナー、参照資料まとめ

こちらのチュートリアルで手を動かすとセミナーの理解がさらに深まります。

https://www.deeplearning.ai/short-courses/chatgpt-prompt-engineering-for-developers/


*0421DS協会_ChatGPTによって描かれる未来とAI開発の変遷.pdf*

https://speakerdeck.com/hirosatogamo/0421dsxie-hui-chatgptniyotutemiao-kareruwei-lai-toaikai-fa-nobian-qian?slide=77

The Future of Work With AI - Microsoft March 2023 Event

https://www.youtube.com/watch?v=Bf-dbS9CcRU

Self-Consistency Improves Chain of Thought Reasoning in Language Models

https://arxiv.org/abs/2203.11171

Language Models can Solve Computer Tasks

https://arxiv.org/abs/2303.17491

Grounding Large Language Models in Interactive Environments with Online 

Reinforcement Learning

https://arxiv.org/abs/2302.02662

ReAct: Synergizing Reasoning and Acting in Language Models

https://arxiv.org/abs/2210.03629

Task-driven Autonomous Agent Utilizing GPT-4, Pinecone, and LangChain for Diverse Applications

https://yoheinakajima.com/task-driven-autonomous-agent-utilizing-gpt-4-pinecone-and-langchain-for-diverse-applications/

Twitter

https://twitter.com/yoheinakajima/status/1640934493489070080?lang=en


【Prompt Engineering】LLMを効率的に動かす「ReAct」論文徹底分解！

https://zenn.dev/ryo1443/articles/d727b2b9a6d08c

LangChain Agentメモ

https://note.com/mega_gorilla/n/n44e99b0ca519

【GPT】今日から使えるOSSライブラリまとめ

https://qiita.com/sonesuke/items/56a6e4b6532eafa104f4

LLM連携アプリの開発を支援するライブラリ LangChain の使い方 (1) - LLMとプロンプト・チェーン

https://note.com/npaka/n/n61ad59380a43

【GPT-4】プロンプト内プログラム×再帰処理×焼きなまし法をやってみた / 一定の確率でチルノ参上！

https://qiita.com/moepy_stats/items/aa22e659cdb2ef4350b1

LangchainでChunk分割とChainTypeをチャンとやって精度と安定性を高める 基本

https://ict-worker.com/ai/langchain-chunk.html

OpenAI 言語モデルごとのエンコーディング一覧

https://zenn.dev/microsoft/articles/3438cf410cc0b5

OpenAI 言語モデルで日本語を扱う際のトークン数推定指標

https://zenn.dev/microsoft/articles/dcf32f3516f013

【まとめ】ChatGPT、GPT-4のAPIリクエストパラメータ

https://note.com/en2enzo/n/n79df81cc291b

Microsoft が LLM をアプリ開発に統合するための OSS「Semantic Kernel」を発表

https://qiita.com/nohanaga/items/430b59209b02c298ef2a

ChatGPTで独自データを利用できるLlamaIndexはどんな仕組みで動いているのか？調べてみました

https://dev.classmethod.jp/articles/llamaindex-overview/

Azure で ChatGPT × Cognitive Search を使ったエンタープライズサーチを実現

https://qiita.com/nohanaga/items/803c09b5a3a4e2d1776f


ChatGPTを使ったサービスにおいて気軽にできるプロンプトインジェクション対策

https://qiita.com/sakasegawa/items/09d9f6a485108f5a618a

【ChatGPT】プロンプトインジェクションの「概要と対処法」まとめ

https://zenn.dev/umi_mori/articles/chatgpt-prompt-injection

画像とテキストの処理を使用した AI エンリッチメント

https://learn.microsoft.com/ja-jp/azure/architecture/solution-ideas/articles/cognitive-search-with-skillsets

Microsoft の責任ある AI の基本原則

https://www.microsoft.com/ja-jp/ai/responsible-ai?activetab=pivot1%3aprimaryr6
OpenLiberty with MicroProfile TelemetryでNew Relicにトレース情報を送る

この記事ではオブザーバビリティプラットフォームのSaaSであるNew RelicにMicroProfile Telemetryでトレース情報を送信する方法について記載します。以前に投稿したOpen Libertyで動かしたアプリのトレース情報をMicroProfile Telemetryで収集・送信する記事の関連記事です。

前回は分散トレース基盤OSSのJaegerにトレース情報を送信しました。しかしSaaSをトレース情報の送信先として利用する場合はOpen Libertyのドキュメントにはやり方の解説がないため、この記事で試すことにします。

https://qiita.com/Ponzmild/items/ef58e01f30007181101b


## 事前準備

New Relicのアカウント取得済みであることを前提とします。
2023年4月時点ではStandardプランの無料枠を活用します。

また、使用するアプリケーションは以前の記事を流用するため、変更点のみこの記事で記載するものとします。


## 本記事で使用するコンポーネント

本記事では以下のコンポーネント・バージョンで動作確認を行なっています。
各コンポーネントの別バージョンでは動作しない可能性がありますので、本番投入する際には事前に手元で動作確認することをお勧めします。

|コンポーネント名|バージョン| 
|:--|:--|
|JDK|OpenJDK 17.0.6 (IBM Semeru Runtime Open Edition)|
|Open Liberty|23.0.0.3|

```bash
$ java -version
openjdk version "17.0.6" 2023-01-17
IBM Semeru Runtime Open Edition 17.0.6.0 (build 17.0.6+10)
Eclipse OpenJ9 VM 17.0.6.0 (build openj9-0.36.0, JRE 17 Mac OS X aarch64-64-Bit 20230117_255 (JIT enabled, AOT enabled)
OpenJ9   - e68fb241f
OMR      - f491bbf6f
JCL      - 927b34f84c8 based on jdk-17.0.6+10)
```

## New Relicのライセンスキーの発行

New Relicにトレース情報を送信するには、New Relicと接続するための認証情報が必要です。
事前に認証のためのライセンスキーを発行してメモしてください。

[APIキーのページ](https://one.newrelic.com/admin-portal/api-keys/)から Type = `INGEST - LICENSE` のキーを控えます。


## MicroProfile Telemetryの設定

トレース情報を送信するアプリにNew Relicに関する設定値を登録します。
設定値は環境変数でも指定可能ですが、今回はMicroProfileを利用しているのでMicroProfile Configの設定ファイル `microprofile-config.properties` に指定します。

設定値はOpenTelmetryエンドポイントとライセンスキーの2つを指定します。Jaegerの場合と異なりライセンスキーの指定が必要なので、`otel.exporter.otlp.headers` に KEY=VALUE 形式でライセンスキーを指定します。

`src/main/webapp/META-INF/microprofile-config.properties`

```properties
otel.sdk.disabled=false
otel.traces.exporter=otlp
otel.exporter.otlp.endpoint=https://otlp.nr-data.net:4317
otel.exporter.otlp.headers=api-key={ライセンスキー}
otel.service.name={アプリ名}
```

## 稼働確認

設定値を登録したら2つのアプリケーションを起動します。次のMavenコマンドでアプリケーションをOpen Libertyの開発モードで起動します。「Liberty is running in dev mode.」とコンソールに表示されていれば起動OKです。

```bash
# フロントエンドUI
cd frontendUI
mvn clean liberty:run

# バックエンドサービス
cd backendServices
mvn clean liberty:run
```

ブラウザで http://localhost:9090/eventmanager.jsf を開いて適当に参照、作成、更新、削除と操作します。アプリの標準出力にエラーが出ていなければNew Relicにトレース情報が送信されているはずです。


## New Relicの探索

New Relicの画面でトレース情報を参照してみます。

New Relicのトップ画面左メニューの「Traces」を開くと、トレース情報を送信したアプリ名が一覧に表示されています。

![スクリーンショット 2023-04-24 18.23.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137947/f498ac44-23e3-98d4-3eee-9ac939f57304.png)

続いてトレース情報の詳細をTrace Groupsの任意のHTTPメソッドからドリルダウンして表示します。
とあるトレース情報を参照すると次の図の通りアプリ間通信のマップ、トレーススパン、スパンの詳細が表示されます。スパンの詳細を確認するとJaegerの場合と同等の属性値が参照できますね。

![スクリーンショット 2023-04-24 18.26.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137947/ff953b95-7e6a-b50d-3e9a-29dc1a731104.png)


## 参考

https://docs.newrelic.com/jp/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/get-started/opentelemetry-tutorial-java/

https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#otlp-exporter-span-metric-and-log-exporters
AWS Summit 2023 参加レポート【2/3】

# はじめに
AWS Summit 2023に参加してきました。

(下記、[AWS DeepRacer](https://aws.amazon.com/jp/deepracer/summit-circuit/)の最終戦の時の様子。最終戦で上位2グループがまさかの世界記録更新＆同点で、この後2回目の最終戦が繰り広げられました。盛り上がりがすごかったです)
![awssummit_20.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/42cc70ec-93cb-16f1-9d5f-927c6a01bd2c.jpeg)
![awssummit_19.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/d886fc40-4528-e638-b113-48cb9cb6207f.jpeg)

自分の振り返りと一緒に、何回かにわけ、受けたセッションの内容を紹介したいなと思います。

# 事例セッション②- 株式会社FLUX
* 題名: AWSで実現するデジタルマーケティングの未来
* 概要: 急成長スタートアップであるFLUXが抱える課題とその解決策を紹介されていた

## 株式会社FLUX 事業内容
* 「テクノロジーを簡単に、経済価値を最大化する」をミッションに、パブリッシャーと広告主向けにオンライン売上を最大化する様々なSaaSサービスを提供。
    * [FLUX AutoStream](https://flux.jp/service/): ユーザのサイト内にタグを設置、データ取得をし、AIによるユーザの自動セグメンテーションを行うことにより、オンライン売上を最大化するサービス
        * タグ: 広告を経由してWebサイトにきたユーザーを判別、そのユーザがコンバージョンタグの設置されたサイトに到達すると、広告の効果による成果としてコンバージョンタグが記録・管理する
    * [FLUX Targeting](https://flux.jp/service/targeting/): AIでInstagram広告やGoogle広告などの運用型広告において、タグを設置、データを取得、AIによるオーディエンス(広告の受け手)を自動最適化するサービス
        * 新規・リターゲティング対象の中から、よりCV(コンバージョン)寄与しやすいオーディエンスを絞り込み、最適化する

## ワークフロー
* ユーザのサイトに埋め込んだタグが取得するアクセスログ等のデータをDBに保存
* DBを分析しモデルを作成し、それを使い独自のAPIを作成
* オーディエンスの購買スコアをつけ、それをユーザのサイトに共有することで、オーディエンス最適化を行う
* 上記フローを回すことで、広告のパフォーマンスを上げている

## 課題
* スループット(単位時間あたりの生産性)と継続性が不十分で、満足できるサービスを提供できていない
    * MLパイプラインが構築できていない
        * 毎日30TBほどの大量データを扱っており、ローカルで気軽に作業できないのにも関わらず、検証環境がない
        * モデル管理の仕組みが不十分で、再現性が担保できない
        * 専門家集団で個人の技術セットは高いが、環境が整っていないため、それが生しきれていない
    * 要件定義が固まっていない
        * ビジネスサイドの要件により、プロダクトの要件もころころと変わっていくため、開発が思うように進まない
    * 人材不足
        * データサイエンティストは十分確保できているが、インフラエンジニアが不在
        * ワークフローをまわす人材はいるのに、ワークフローの環境構築ができない状況
        * 予算的にインフラエンジニアを増やすわけにもいかない...

## 解決策
* AWS技術サポートとタッグを組み、ハンズオンを開催したりなどしながら、検証環境を構築した
* 旧アーキテクチャ(Jupyterhub)から新アーキテクチャ(Sagemaker)への移行準備では、[Amazon SageMaker Studio Lab](https://aws.amazon.com/jp/sagemaker/studio-lab/)を活用し、Jupyterhubでの作業内容をいい具合にマージすることができた
    * Amazon SageMaker Studio Lab: セットアップ不要の無料のSagemaker開発環境。MLを学び、実験することができる
* 旧→ 新アーキテクチャへの移行期間は10日程度
* 新アーキテクチャになってから、3営業日掛かっていたワークフローが0.5営業日に、大幅な業務効率化を実現した
    * 検証環境をつくったことで、一週間で数回学習モデルの更新が可能になった
    * モデル保存の部分でSageMaker Model Registryを採用し、モデルカタログを作成・管理できるようになった
    * 学習部分(Sagemaker Training Job)では、スポットインスタンスを活用することでコスト効率化ができた

![awssummit_11.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/7945f912-ab91-8386-89af-8ff30951a183.jpeg)

# 感想
* 課題の部分、特に要件定義が定まらずスループットが不十分という点は、(大なり小なりどの企業でも抱えてはいるだろうが)スタートアップならではだなと思ったし、特有の大変さを感じた
* MLパイプラインの部分は、完全に今所属している組織で抱えている課題と全く一緒で、本当にどの企業も通る道なのだなと思った(↓過去にブログにまとめているので、よかったら読んでみてください)

https://qiita.com/ririco/items/e90dddcc2f9863a167ea

* インフラエンジニア不在の中、AWSからのサポートのみでここまでやり遂げたスピード感やバイタリティはかなりすごいなと思ったし、個人的にちょっとスタートアップで働くの面白そうだなと感じた
* ちなみに、今の会社ではPOCは完了したが実際の商用環境への移行が中々できないでいる。うちはデータサイエンティスト側の稼働に空きがなく、そこまで手が回っていない。重ねて、大きな移行になるので、どうしても慎重になる(失敗した時の損害がでかい)。だからと言って先延ばしにせず、確実に改善を進めるべきだなと思いました。反省。