$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

運動が脳に好影響を与えることを紹介する本を読んだ

最近少しだけ太ってきたなと感じたので運動を始めることにした。せっかくやるなら運動のモチベーションを上げたいなと思い、運動が脳に与える効果について書かれた本を2冊読んでみた。

これらの本は、どちらも運動が脳に与える好影響について、科学的な研究結果をもとに解説している本だった。直近の運動のモチベーションを上げる効果があったので非常に良かった。

今回学べたのは次のポイント。

  • 運動にはストレス軽減、集中力の強化、記憶力の向上、創造性の促進など、脳への多くの効果がある
  • 脳への好影響を与えるには、最大心拍数の70%以上に上げる有酸素運動をできれば30分以上、最低20分以上行うと良い

これまで運動は身体的および精神的な健康のためにやるべきと考えていた。そのため自分が学習したい・開発したいという気持ちと運動する時間がトレードオフの関係にあると感じていて、どうしても運動を後回しにしてしまっていた。

しかし今回の本で、運動が学習の効果を上げることが出来そうと感じることが出来た。そのためトレードオフという感覚がなくなり、「学習のために運動する」という考え方にスイッチできたのが良かった。

これらの本が推奨するのは有酸素運動30分以上であるが、流石に初めから実践するのはハードルが高い。また1日の途中で運動をやるのも意志力が必要だ。そこで、まずは朝いつもより20分程度早起きをし、水を一杯飲んだ後、10-20分程度の運動をする習慣をつけることから始めたいなと思った。

読書ノート

「脳を鍛えるには運動しかない!」

- 最大心拍の60~70%を保って35分運動するだけで、認識の柔軟性が向上する 69
- 頭のキレを保つために30分のジョギングを週に2~3回、12週間続けると能力が向上する 71
- 有酸素運動と複雑な動きはそれぞれ別の有益な効果を脳にもたらす 71
    - 複雑な運動技能はBDNFを向上させる
    - BDNFは学習能力、精神的な状態の両方とも改善する
- 毎週50分運動すると鬱になる確率が50%低下 158
- 低強度(ウォーキング)、中強度(ジョギング)、高強度(ランニング)の区切りのどれに入るかを意識する 313
    - 低強度 = 最大心拍の55-65
    - 中強度 = 65-75
    - 高強度 = 75-90
    - 最大心拍 = 220 - 年齢
    - 高強度でのトレーニングの効果は絶大
- 理想は、週に6日、45-60分の有酸素運動。4日は中強度で長めに、2日は高強度で短めに 315

「運動脳」

- 週に2回以上運動をしている人はストレスや不安とほぼ無縁 70
    - 少なくとも20分は続ける
- 運動は選択的注意力と集中力を改善する 90
- 目の前のことに集中するにはドーパミンが必要 105
    - ドーパミンの量を増やすにはウォーキングよりランニング
    - 心拍数の目安は70-75%。運動は朝に、可能であれば30分 122
- BDNFを増やせるのは有酸素運動の中でもインターバルトレーニング 142
    - 60秒激しく動いて60秒休むを10回
- 定期的に運動すると皮肉っぽい気質や神経質な性格の人が少ない。周囲の人たちとも互いに理解し合えていると感じる 146
- ランナーズハイで意欲を高めるには30-40分のランニングを週に3回 155
- 創造性を高めるなら30分のランニング。効果持続は1時間から数時間 202
- 立って作業をすると脳が効率よく働く 230
- 脳のための最高のコンディションを保つのは、ランニングを週に3回、45分以上。筋力トレーニングより有酸素運動 272
- 関係する物質の役割 282
    - ドーパミン 気分を制御する物質で、とくに動機づけや意欲、報酬を制御している神経伝達物質。また、集中力や動作とも密接に関わっている
    - セロトニン 脳内で分泌される物質で、感情、とくに情緒の安定や前向きな精神力を促す作用がある。
    - ノルアドレナリン 脳内で分泌される物質で、主に用心深さや集中力を促す作用がある。
    - BDNF(脳由来神経栄養因子) 脳が生成するタンパク質で、脳細胞の新生や記憶力、全般的な健康など、脳の様々な働きを促進する作用がある。
    - エンドルフィン 体内性モルヒネ(エンドジーナス・モルフィン)。脳(と身体)で生成されるホルモンで、鎮痛作用があり、多幸感をもたらす。このエンドルフィンと内因性カンナビノイドが「ランナーズハイ」を引き起こしていると考えられている。

AIによる開発の前提知識を学ぶため「LLMのプロンプトエンジニアリング」を読んだ

LLMアプリケーションを作ることがなかったとしても、業務でAIを活用する上で大前提を知っておくと役立ちそうということで、「LLMのプロンプトエンジニアリング」を読んだ。

実際に読んでみると、紹介されているLLMの特性を知っておくと、AIコーディングなどにもかなり役立ちそうで良かった。

たとえばこの本に載っている以下のような特徴は非常に参考になる。

  • テキストを一度しか読めず後戻りできない。そのため先に書かれた内容のみを考慮して後に繋げる
  • 気が散りやすい。「うまくいけば」役立つかもしれない無用な情報でプロンプトを埋めないようにする
  • 人間であるあなたが完全に展開されたプロンプトを理解できないのであれば、LLMも同様に混乱する可能性が非常に高い。
  • 導かれる必要がある。何を達成すべきかについて明示的な指示を提供し、必要ならタスクをどのように進めるべきかを示す例を提供すべき。
  • 内的な独り言がない。問題について声に出して考えること(思考の連鎖、CoT)を許可されれば、有用な解決策に到達するのがはるかに容易になる
  • プロンプトの末尾に近い情報ほど、モデルに大きな影響を与えやすい
  • 中間部を喪失しやすい。プロンプトの冒頭と末尾の情報は比較的思い出しやすいが、中間に埋め込まれた情報は活用が難しくなる


適切に構築されたプロンプト構造の話も参考になった。

  • 構造は、導入 => コンテンツ => リフォーカス => 移行の順
  • 導入部: 生成するドキュメントの種類を明確にし、残りのコンテンツに正しくアプローチ。後に続く全ての内容のコンテキストを設定して、モデルに問題を最初から考えさせる役割。早い段階で焦点を絞る
  • リフォーカス: すべてのコンテキスト要素を入れ終わったら、最後にもう一度、本題の質問をリマインド。導入部とサンドイッチにする
  • 移行: 問題の説明から問題の解決へ移ったことを示す

このように開発へのAI活用の大前提として参考になる内容が多かったのでおすすめ。

読書ノート

- LLMはテキストを一度しか読めず後戻りできない。そのため先に書かれた内容のみを考慮して後に繋げる 79 ⭐️
    - 気づき: これが指示はまず最初にと言われる所以っぽい
- 人間の評価者がモデル内部の知識状態を正確に把握して解答例を作るのは困難なため、2つの悪い状況が生じる 90
    - 人間がモデル以上の知識を前提に解答例を作る。この場合は「知らないことをでっち上げても構わない」と学習してしまう
    - 人間がモデルの知識を過小評価して解答例に曖昧な表現を使う。この場合「確信があっても常にぼかして答える」ことを学習してしまう
    - => このような問題をRLHFで
- ユーザーの問題をLLMに解釈できるようにするための条件 122
    - トレーニングデータのコンテンツとよく似た形式でなければならない
        - 評論形式、Markdown形式などなど
    - ユーザーの問題解決に必要なすべての情報が含まれてなければならない
    - モデルが問題解決に役立つ補完を生成するように誘導されなければならない
    - 自然な終止点があり、世々が自然に止まるようになっていなければならない
        - パターンを作り、stop wordが効くように

### プロンプトに組み込むソースを検討する
- プロンプトに組み込むソースは、大きくは「静的」「動的」がある 158
- 静的なコンテンツ
    - 質問の明示的な「明確化」162
        - 指示だけでなく、なぜそのルールが必要か理由を付ける。殺してはいけない => 殺傷行為は他者の生存権を侵害するため、避けるべきです
        - 過度に厳格な表現は避ける。絶対に殺してはいけない => 生命を奪う行為は極めて限定的な状況でのみ検討し、その妥当性を慎重に判断してください
    - 暗黙的な指示
        - Few-shotプロンプティング 171
            - 欠点: Few-shotプロンプティングはモデルが例示された情報に偏る
            - 欠点: 誤ったパターンを認識することがある。正常系 => 異常系と並べてFew-shotすると、異常系を出力してしまうなど
- 動的なコンテンツ
    - 収集時の考慮点 179
        - 動的に収集するときの待ち時間
        - 質問の事前に準備できるか
        - コンテンツの優先度を比較可能で、後から取捨選択できるか。有用性、依存関係など
    - 利用する動的コンテンツを見つける流れ: モデルが知りたそうな情報のマインドマップを作り、アプリケーションが実際に取得可能な情報を洗い出し、まず手軽なものから実装し、プロジェクトが進むにつれて複雑なソースにも手を出す 185
    - モデルは与えられた情報を必ず活用しようとする傾向にあるため、無関係なコンテキストまで深読みしてしまう 188

### プロンプトの組み立て
- 適切に構築されたプロンプト構造 216 ⭐️
    - 導入部: 生成するドキュメントの種類を明確にし、残りのコンテンツに正しくアプローチ。後に続く全ての内容のコンテキストを設定して、モデルに問題を最初から考えさせる役割。早い段階で焦点を絞る
    - リフォーカス: すべてのコンテキスト要素を入れ終わったら、最後にもう一度、本題の質問をリマインド。導入部とサンドイッチにする
    - 移行: 問題の説明から問題の解決へ移ったことを示す
- LLMに共通する2つの特徴 216
    - コンテキスト内学習: プロンプトの末尾に近い情報ほど、モデルに大きな影響を与えやすい
    - 中間部の喪失: プロンプトの冒頭と末尾の情報は比較的思い出しやすいが、中間に埋め込まれた情報は活用が難しくなる傾向
- プロンプト要素の関係を考える時、ポジション(並びと場所)、重要度、依存関係を考慮する 242
    - 依存関係 = 必須条件(ある要素を含めるなら前提として必ず入れる)と火両立条件(同時に使えない。要約版と詳細版があった時、どちらも使うと混乱する)がある
- 最小限のプロンプトクラフター:プロンプト要素を順序付けし、トークン予算に収まる限り末尾の要素を可能な限り多く保持する 248
- 補完がどのくらい優れているか 262
    - logprobはトークンの各選択肢に対するモデルの信頼度
    - トークンの信頼度だけでは文書全体の信頼度はわからないが、テキスト全体のlogprobを合計すると全体的な信頼度を示す

### LLMワークフロー
- ワークフローの構築に必要な手順
    - 1. 目標定義: ワークフローが達成する望ましい出力や変更は何か
    - 2. タスク指定: 目標を達成する一覧のタスクへ分割。各タスクの入出力を特定
    - 3. タスク実装: それぞれを実装し、各タスクが単独で正しく動作することを確認
    - 4. ワークフロー全体に接続: ワークフロー全体のコンテキストの中でタスクが正しく機能するように、タスクを調整することもある
    - 5. ワークフロー最適化: 品質、パフォーマンス、コスト

### 評価
- LLMアプリにおけるテストスイートは、その変化が改善かリグレッションかを自動的に判別する方法がない。この点が通常のソフトウェアテストと違う 386
- テストを行うLLMとテストを考案するLLMが同一だった場合、テスト結果にバイアスがかかる問題が存在 394
- 評価させる時は、モデルが第三者を採点していると考えさせる方が良い 404
    - モデル自体を採点していると考えてしまうと、バイアスにさらされて精度が悪化する
- 人気のベンチマークは、ベンチマーク自体をLLMが学習していくため、徐々に使えなくなってしまう 426

### LLMの特性として覚えておきたいこと
430 ⭐️
- LLM は気が散りやすい
    - 「うまくいけば」役立つかもしれない無用な情報でプロンプトを埋めないでください。すべての情報が意味を持つようにしましょう。
- LLM はプロンプトを解読できない
    - 人間であるあなたが完全に展開されたプロンプトを理解できないのであれば、LLMも同様に混乱する可能性が非常に高いです。
- LLM は何かに導かれる必要がある
    - 何を達成すべきかについて明示的な指示を提供し、適切な場合は、タスクをどのように進めるべきかを示す例を提供してください。
- LLM は超能力者ではない
    - プロンプトエンジニアとして、モデルが問題に対処するために必要な情報をプロンプトに含めることはあなたの仕事です。あるいは、モデルにツールと指示を与えて、それを取得できるようにしましょう。
- LLM には内的な独り言がない
    - LLM が問題について声に出して考えること(思考の連鎖、CoT)を許可されれば、有用な解決策に到達するのがはるかに容易になります。

「Go言語で学ぶ並行プログラミング」を読んだ

最近はGoの並行プログラミングを学んでおり、ちょうど「Go言語で学ぶ並行プログラミング」という本が出たばかりだったので読んでみた。この本は自分にめちゃくちゃ刺さって面白かった。

この本はGoで並行プログラミングをどうやるかという本ではない。そうではなく並行プログラミングの概念が分かりやすいGo言語を活用することで並行処理の原則や技術を学べる本になっている。そのため、Goを使って独自にRWMutex、Semaphore、WaitGroup、channelを実装していきながら理解を深めていく内容となっている。実装することが一番理解を深める良いやり方と自分も感じているため、とても参考になった。

実際に本を読みながら写経してみたのはこちら。

プログラミング言語を問わずに並行プログラミングの理解を深めたい人におすすめでした。

読書ノート

- 実行と資源は分離できる。新しいスレッドを作る時OSが作るべき資源は実行のための資源しか不要 41
- ユーザーレベルスレッドの欠点 50
    - ブロッキング呼び出しを行うとプロセス全体がOSのタスクスケジュールから外れる
    - 複数のユーザーレベルスレッドがあっても1コアしか使えない
- ワークスティーリングの様子 52
- ReadWriteMutexを自作する 102
    - [実際の実装](https://github.com/shibayu36/go-playground/blob/f0cbf8ddb12cb8d0863dc99db7dcc3848d9f9e62/playground/read_write_lock_test.go)
- 条件変数を使うパターン図 110
- 条件変数のコード例 113
- 条件変数を扱うときはロックを確保している時のみメソッドを使う必要がある 117
- 書き込み優先のRWMutexではRLockが複数取れるからといって、再帰的な呼び出しをすると問題が起こる 122
    - 再帰処理の先頭でRLock取得 => 他からWLock(待ち) => 再帰の2番目でRLock(待ち)で、先頭のRLockが解放されなくなる
- ライター優先のRWMutex。Broadcastしているタイミングがちゃんと理解できてない 124
    - Lockのforから抜けるタイミングの場合でBroadcastしてるかな
- セマフォを実装する 128
    - [実装例](https://github.com/shibayu36/go-playground/blob/f0cbf8ddb12cb8d0863dc99db7dcc3848d9f9e62/playground/semaphore.go)
- 独自でWaitGroupの実装 137
    - [実装例](https://github.com/shibayu36/go-playground/blob/f0cbf8ddb12cb8d0863dc99db7dcc3848d9f9e62/playground/wait_group.go)
- 全員が揃ったら一斉にタスクをスタートさせる仕組みを取り扱うのがバリア 145
    - 全員が揃ったら一斉にタスクをスタートさせる仕組みを取り扱うのがバリア 145
    - ステップごとに簡単に同期が取れるというのは面白いかも https://chatgpt.com/c/6796d470-bb68-8010-b8c4-4c3a545fcf40
- channelの独自実装 175
    - [実装例](https://github.com/shibayu36/go-playground/blob/f0cbf8ddb12cb8d0863dc99db7dcc3848d9f9e62/playground/my_channel_test.go)
- selectでnilチャネルの送信・受信をすると、そのチャネルを使わないので、そのケースをストップさせる効果がある 195, 具体例 198
- メッセージパッシングとメモリ共有のどちらを選択するか。大量データ or 膨大なメッセージ数ならメモリ共有を選択する余地がある。それ以外はメッセージパッシングの方が良い 207
- チャネルメッセージパッシングのガイドライン 212
    - データのコピーだけを渡す
    - できるだけ、メッセージパッシングとメモリ共有を混在させない
- パイプラインのパターン 220
- ファンインの場合、多対1の1側のチャネルをどのタイミングで閉じるか問題がある 222
    - WaitGroupを使ってcloseを単一にするのは面白い
- チャネルで受け取った値を多数のチャネルへBroadcastパターン 228
- 前のgoroutineの処理を待つパターン 250
- ワーカープールパターンで、select defaultを使ってワーカーがmaxの時にビジーを即時に返す 259
- 取引に関係する全ての口座をロックを実現するために条件変数を利用する 288
- Goではフューテックスを直接使わずに同様のキューシステムを実装している 319
    - フューテックスを直接使うとカーネルレベルスレッドが一時停止される可能性がある