(DMの履歴からAIチャットボットを作成する。)

  今回はインスタのDMの履歴からAIチャットボットを機械学習させて作ってみようと思います。

 

ステップ

① DMの履歴をjson形式でダウンロード。

② 会話を機械学習できる形に整理する。

③ ollamaをインストール  ←要らなかった

④ LoRA微調整で既存の大規模llmに自分の会話風になるように重みをつける(機械学習)

⑤ テスト

⑥ 簡単なアプリケーションを作ってチャットボット化 ←次回

 

■実際に作っていく。

①DMの履歴をjson形式でダウンロード。

1、下記の要領でDMの履歴をエクスポートする画面までいく

・インスタグラムにログイン > プロフィールのはぐるまをクリック > Meta認証 > あなたの情報とアクセス許可 > あなたの情報をエクスポート

 

2、json形式でダウンロード

・下図が表示されたら「エクスポートを作成」で手順に沿いながらフォーマットをjsonダウンロードするにし、項目を「メッセージ」のみにする。

3、数時間たったら登録しているメールアドレスにzipファイルが届くのでわかりやすい場所に展開して保存する。

 

②会話を機械学習できる形にする。(パース)

◎簡単なプログラムの動作解説

1,DMしたユーザー名の下にjsonファイルがあるファイルをひとまとめにしたファイルを参照

2,文字化けを解消

3,URL、メール、電話番号などの個人情報と300字以上の長文を削除

4,DMのjson形式から会話がセットになった形式からパースする。

import json
import glob
import re
import os

BASE_DIR = r"C:\Users\ユーザー名\Desktop\DM_jsonファイル"
OUTPUT_FILE = os.path.join(BASE_DIR, "insta_finetune.jsonl")

def fix_encoding(text: str) -> str:
    """文字化けをUTF-8に戻す"""
    try:
        # 文字化けしている場合(ãなど)を再変換
        text = text.encode('latin1').decode('utf-8')
    except Exception:
        pass
    return text

def clean_text(text):
    """URL・メール・電話番号などを除去して整形"""
    if not isinstance(text, str):
        return ""
    # 文字化け修復
    text = fix_encoding(text)
    # URL削除
    text = re.sub(r"http\S+|www\.\S+", "", text)
    # メール削除
    text = re.sub(r"\S+@\S+", "", text)
    # 電話番号削除
    text = re.sub(r"\d{2,4}-\d{2,4}-\d{4}", "", text)
    # 英数字だけの文を除外
    if re.fullmatch(r"[\x00-\x7F]+", text):
        return ""
    # 絵文字削除
    text = re.sub(r"[\U00010000-\U0010ffff]", "", text)
    # 空白トリム
    text = text.strip()
    return text

train_data = []

json_files = glob.glob(os.path.join(BASE_DIR, "**", "message_*.json"), recursive=True)
print(f" 発見したJSONファイル数: {len(json_files)}")

for file in json_files:
    with open(file, encoding="utf-8") as f:
        try:
            data = json.load(f)
        except json.JSONDecodeError:
            print(f"⚠️ JSON読み込み失敗: {file}")
            continue

        messages = data.get("messages", [])
        messages = sorted(messages, key=lambda x: x.get("timestamp_ms", 0))

        for i in range(len(messages) - 1):
            m1, m2 = messages[i], messages[i + 1]
            if "content" not in m1 or "content" not in m2:
                continue

            text1 = clean_text(m1["content"])
            text2 = clean_text(m2["content"])

            if not text1 or not text2:
                continue
            if len(text1) > 300 or len(text2) > 300:
                continue

            train_data.append({"input": text1, "output": text2})

with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
    for item in train_data:
        f.write(json.dumps(item, ensure_ascii=False) + "\n")

print(f"\n✅ 完了: {len(train_data)}件の会話ペアを保存しました。")
print(f" 出力ファイル: {OUTPUT_FILE}")

 

とりあえず今回用意した機械学習用の会話ペアは3520件です。

下図がパースし終わったプログラム。

 

③ollamaをインストール

・まずollamaとは大規模言語モデルをローカルで実行できるオープンソースのツールで、windows/mac/linuxで動作します。動作もそれほど重いわけではありません。

1、https://ollama.com/downloadから自分の環境にあったものをダウンロード。

2、cmdで下記を実行。

ollama run llama3

本題とは関係ないですが、せっかくなのでollamaを動かしてみましょう。

ollamaはモデルでllmをローカルで実行するだけのツールなのでこちらで使うモデルを指定する必要があります。③ollamaをインストールのとおり今回はllama3を使ってみました。他にも「mistral」などのモデルがあります。他のモデルを使いたい場合にはollama runのあとにモデル名を記述します。

 

動作確認

→ローカルでの実行はGPUのメモリの消費が激しいです。

 RTX3050の場合はメモリ不足で計算がmaxできていない場合がありました。

 (3090欲しい)

 下の例は英語ですが、一応日本語にも対応しています。

 日本語の精度はいまいちで途中で英語になったりする。

それでは本篇へ、、、


 

④機械学習する。

・機械学習といっても計算資源がしょぼいため

 一からモデルをつくるわけにはいきません。そこでLoRAというのを使います。

 モデルの専門性を高くするという技術でファインチューニングという似たもの

 コストがかり、断念しました。

 (精度はLoRAもfine tuningもあまり変わらないらしい)

 

LoRA(Low-Rank Adaptation)

→モデルの重み行列を「低ランク分解」することで、更新するパラメータを大幅に削減できるらしい。

Efficient Fine-Tuning with LoRA for LLMs | Databricks Blog

LoRA(Low-Rank Adaptation)の理論と実践

生成AIのFine tuning(ファインチューニング)とは?基本から最新手法まで

 

・またLoRAするモデルは先ほど試したllma3では大きすぎるため、

 HuggingFaceTB/SmolLM3-3Bという軽いモデルを使います。

 そしてそのモデルを使うのにollamaは使わないのでollamaのインストールは

 必要なかった

 

・量子化について

量子化の基本的な考え方は、ニューラルネットワークで使用される数値の精度を意図的に下げることです。通常、ディープラーニングモデルの重みや活性化(ニューロンの出力)は、32ビット浮動小数点数(FP32)で表現されます。しかし大量のメモリを消費するため個人のお遊び環境では使えません。

 

そのためFP32の値を4bitや8bitに変換します。(今回は4bit)

Q (x) = round ( x S ) + Z

 

ここで、

xは元の浮動小数点数

Sはスケールファクター

Zはゼロポイント(オフセット)です。

スケールファクターSは、元の浮動小数点数の範囲を量子化後の整数の範囲にマッピングするための係数で、整数/元の幅で求まります。

ゼロポイントZは、マッピング後の値が負にならないようにするための数。

ディープラーニングモデルの量子化: PyTorchによる実践解説

 

◎ソースコード (train_lowa.py)

from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model

# ✅ JSONL 読み込み(そのままでOK)
dataset = load_dataset(
    "json",
    data_files="C:/Users/ユーザー名/Documents/Tbot/insta_finetune.jsonl"
)

# ✅ モデルを4bitで読み込み
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM3-3B")
model = AutoModelForCausalLM.from_pretrained(
    "HuggingFaceTB/SmolLM3-3B",
    load_in_4bit=True,
    device_map="auto"
)

# ✅ LoRA設定
lora = LoraConfig(
    r=8,
    lora_alpha=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"]
)
model = get_peft_model(model, lora)

# ✅ トークナイズ(必要最小限)
def tokenize(example):
    text = f"ユーザー: {example['input']}\nアシスタント: {example['output']}"
    tokens = tokenizer(
        text,
        truncation=True,
        max_length=64,
        padding="max_length"
    )
    tokens["labels"] = tokens["input_ids"].copy()   # これが超重要
    return tokens


dataset = dataset.map(tokenize)

# ✅ 学習設定(3050に最適)
args = TrainingArguments(
    output_dir="out",
    per_device_train_batch_size=1,
    gradient_accumulation_steps=16,
    num_train_epochs=2,
    learning_rate=2e-4,
    fp16=True
)

trainer = Trainer(
    model=model,
    args=args,
    train_dataset=dataset["train"]
)

trainer.train()
model.save_pretrained("my-bot")

 

・このコードを動かすにはpytorchをインストールしておく必要があります。

 rtx3050用インストールコマンド(CUDA 11.8)

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

・確認コマンド

import torch
print(torch.cuda.is_available())         # True である必要あり
print(torch.cuda.get_device_name(0))     # "NVIDIA GeForce RTX 3050" と出るはず

 

◎学習結果

・以下のようなファイルができあがります。

ファイル名 / ラベル 役割 / 意味
adapter_model.safetensors 学習された LoRA 重みそのもの
adapter_config.json LoRA設定(r, α, 対象層など)
config.json 元モデルの設定コピー
generation_config.json 推論時の設定
special_tokens_map.json 特殊トークン対応
tokenizer.json / tokenizer.model トークナイザ
tokenizer_config.json トークナイザ設定
trainer_state.json 学習進行状況(loss など)
training_args.bin TrainingArgumentsの保存
events.out.tfevents... TensorBoardログ
pytorch_model.bin / .safetensors チェックポイント時点の LoRA 付きモデル
optimizer.pt オプティマイザー状態(再開用)
scheduler.pt 学習率スケジューラ状態
trainer_state.json その時点の学習情報
rng_state.pth 乱数状態
model-00001-of-00002.safetensors オフロードされたモデル分割データ
model.safetensors.index.json シャードのインデックス
zero_shard.json(ある場合) ZeROオフロード管理

 

 

⑤テスト (chat_test.py)

・とりあえずどんな対話ができるのかテストしてみます。

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch


# GPUが使えるか確認
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using device:", device)

# 学習済みモデルとトークナイザーをロード
model = AutoModelForCausalLM.from_pretrained("my-bot").to(device)
tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM3-3B")

# 対話ループ
while True:
    user_input = input("ユーザー: ")
    if user_input.lower() in ["exit", "quit", "終了"]:
        break

    prompt = f"ユーザー: {user_input}\nアシスタント:"
    inputs = tokenizer(prompt, return_tensors="pt").to(device)

    outputs = model.generate(
        **inputs,
        max_new_tokens=100,
        do_sample=True,
        temperature=0.7,
        top_p=0.9
    )

    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    print(response)

 

会話

ユーザー: こんにちは
アシスタント: すごい!
ユーザー: なにがやねん

アシスタント: 笑笑

ユーザー: 世界で一番高い山はなに?
アシスタント: アマゾン山?
ユーザー: ちゃうわ、あほやな

アシスタント: えー?笑笑笑

 

見てのとおりめちゃくちゃあほです。

しかも複数人のDMを読み込んでいるため人格が混ざっている感じがします。

もしかしたらベースのモデルを読み込めてないのかも。

やり方が間違っているかもしれないのでアプリケーションとして完成させるのはこの先になりそう。

             (Cの開発環境を作る

 今回はC言語の開発環境を構築していきます。

 

これまではpythonとarduino言語を主に使っていましたが(これからも)Cで動かしてみたいコードができたので環境構築することに決めました。

 

VScodeでCを使うにはpythonのように拡張機能をインストールして終わりというわけではなくより複雑で注意点がいくつかあります。そこで今回は自分用の忘備録として手順をまとめておきます。

 

すべての作業が完了してから記事を書いているので途中のスクリーンショットなどはぼありません詳しくは参考URLを参照してください。

■手順

① MinGW64をGitHubからダウンロードする
以下のリンクからMinGW64をダウンロードします。

https://github.com/niXman/mingw-builds-binaries/releases/download/15.1.0-rt_v12-rev0/x86_64-15.1.0-release-win32-seh-ucrt-rt_v12-rev0.7z

 

②ダウンロードした7zファイルを解凍し、C:\Program Files (x86) の中に

 フォルダーごと配置します。

③ PATHを追加する
1,タスクバーの検索ボックスに「環境変数」と入力します。
2,「環境変数を編集」を選択し、PathにMinGW64のbinフォルダーを追加します。
※管理者権限がないとPathの追加ができません。
その場合は、cmdを管理者権限で開き、以下のコマンドを実行してください。

SystemPropertiesAdvanced

⑤C:\Program Files (x86)\mingw64\binと設定

 

 

⑥cmdでインストールされたか確認

・「gcc --version」と入力してENTER

 

※なお、Cドライブにインストールされているため、いつものように任意の場所でフォルダーを作成して実行しても、うまく動作しません(※自分の環境の場合)。
必ず 「C://Users/ユーザー名」 の中にフォルダーを作成し、その中で実行する必要があります。

 

⑦拡張機能が機能しているかはわかりませんが

「code runner」と「C/C++拡張機能」はインストールしておきました。

 

■完成!

・普通にコンパイルできます。

 

 

参考サイト:Visual Studio CodeでC言語をデバッグ実行する環境構築|Aruca

      C/C++をVSCodeで開発するための環境構築 #MinGW - Qiita

      (spotDLを使ってspotifyの曲を無料でダウンロード

  今回はspotifyDLを使って音楽をダウンロードし、ネットが使えない場所でも音楽が聴けるようにしたいと思います。(合法)

 

spotDLとは

Spotifyで配信されている楽曲をYoutube Musicからダウンロードできるツールのこと

 

■spotDLを使うための手順

① Pythonのインストール
・まずPythonをインストールします。Welcome to Python.orgから

 最新版をダウンロードして、「Add Python to PATH」にチェックを入れて

 インストールします。

 

②spotDLのダウンロード

・PowerShellを開いて以下を入力↓

pip install spotdl

③ FFmpegの自動インストール
次に、音声を処理するためのFFmpegを導入します↓

winget install --id=Gyan.FFmpeg -e

これで曲をダウンロードする手順は完了!

あとはspotdlのあとにスペースを空けてspotifyの曲のURLかプレイリストのURLを張ったらwindowsのユーザーのところにmp3が保存されます。


おまけ

スマホにmp3を入れてオフラインで再生するときにはdocumentsが使いやすい。iphon標準搭載されている。filesよりも使いやすいので、mp3以外のファイルの保存にもおすすめ。シャッフル再生や曲を飛ばすこともできます。

 

パソコンからdocumentsにデーターを移すときはiTunesを使うと良いです。

          (icrawlerでネットの画像を収集してみる。

  今回はicrawlerでネットの画像を収集してみます。

目的は機械学習のために大量の写真が必要だったため

 

◎icrawlerとは

→pythonで簡単に画像を収集するためのフレームワークです。

 コードも短くていいので使いやすい。

 

■使い方

 

①ライブラリをインストールする。

pip install icrawler

②コードをかく

・keywordのとこに取得したい写真の検索ワードをかくと自動で作った

 フォルダに写真が保存されます。

・maxが1000なので毎回1000枚取得できるわけではありません。

from icrawler.builtin import GoogleImageCrawler

crawler = GoogleImageCrawler(storage={"root_dir": "C:/ユーザー名/Desktop/ugui_images"})
crawler.crawl(keyword="やまめ_写真", max_num=1000)

 


ほかの取得方法としてはbing image search APIというのがあります。

安定的に大量の画像を取得可能です。またAPIキー取得→検索 → ダウンロード → 保存の流れを自動化できます。


 

■クローリングの実際の流れ
①検索キーワードをGoogle画像検索URLにエンコードして送信
 ページ番号を変えながら複数の結果ページを取得
②各ページのHTMLを正規表現やJSONスニペット解析で解析
 imgurl= や src などのパターンから画像URLを抽出
③URLをキューに格納
④キューからURLを受け取り、requestsなどでGET
⑤画像を保存フォルダ(root_dir)にファイル名付きで保存
 例外時はリトライし、失敗をログに記録

       (物体検知AI YOLOのpythonライブラリを使ってみた

 今回は、物体検知AI YOLOのpythonライブラリを使ってみます。

踏み込んだ内容ではなくとりあえずYOLOのpythonライブラリを使って物体検出を知る第一歩としてやってみます。

 

YOLO(You Only Look Once)とは

→物体検出のためのアルゴリズムであり、リアルタイムでの物体検出を可能にするディープラーニング技術。 YOLOは、画像や動画内の物体を一度の処理で検出することができ、従来の手法に比べて高い精度と速度を誇る。

 

 

とりあえずライブラリを使ってみる。

 

手順

1,VScodeのコマンドにultralyticsライブラリをインストール

pip3 install ultralytics

2,コードを書く

from ultralytics import YOLO

model = YOLO("yolov8n.pt")
results = model("画像URL")

#結果の表示
results[0].show()

3,実行結果

・ミスはありますがまぁまぁの精度だと思います。

 

しかしノートパソコンでは正しく実行できたわけですが、デスクトップパソコンはなぜか下記のような文字列がコマンドラインに表示されました

WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Video stream unresponsive, please check your IP camera connection.
0: 480x640 1 chair, 1 couch, 1 tv, 1 book, 33.0ms
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Video stream unresponsive, please check your IP camera connection.
0: 480x640 1 chair, 1 couch, 1 tv, 1 book, 36.1ms
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Video stream unresponsive, please check your IP camera connection.
0: 480x640 1 chair, 1 couch, 1 tv, 1 book, 33.3ms
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Waiting for stream 0
WARNING Video stream unresponsive, please check your IP camera connection.
0: 480x640 1 chair, 1 couch, 1 tv, 1 book, 31.1ms
WARNING Waiting for stream 0

これが大量に表示される原因はchat gptいわく

 model() に渡している URL が 静止画像ではなくストリーム扱い になっている

 一部の URL だと YOLO が動画ストリームとして解釈することがあります。

ということでした。

 

ストリーム扱いになってるっぽいのでURLから取得した画像を静止画にしてYOLOに物体検出してもらいます。

 

というのを書いた後もう一回処理を実行したら成功しました。

やはりURLがおかしかったようです。

 

成功しましたが、ついでなので静止画にするプログラムも載せときます。


 

静止画にしてから処理するプログラム

処理時間も計測できるようにしました。

from ultralytics import YOLO
import time
import requests
from PIL import Image
from io import BytesIO

# 画像を取得
url = "https://cdn.locari.jp/upload/post_element/picture/8513009/mobile_11-680x680.jpg"
response = requests.get(url)
img = Image.open(BytesIO(response.content))

model = YOLO("yolov8n.pt")

start_time = time.time()
results = model(img)  # ここで PIL Image を渡す
end_time = time.time()

print(f"処理時間: {end_time - start_time:.3f}")

results[0].show()

 

◎処理結果

0: 480x640 3 cups, 3 chairs, 1 dining table, 1 remote, 3 books, 45.0ms
Speed: 19.3ms preprocess, 45.0ms inference, 2.3ms postprocess per image at shape (1, 3, 480, 640)
処理時間: 0.096 秒

 

 

 

最後にノートPCとデスクトップPCの処理時間を計測してデスクトップの必要性が薄れてきた今、デスクトップの威厳を見せます。

from ultralytics import YOLO
import time

model = YOLO("yolov8n.pt")

start_time = time.time()
results = model("https://asajikan.jp/wp-content/uploads/2022/03/IMG_2367.jpg-640x480.jpg")
end_time = time.time()


print(f"処理時間: {end_time - start_time:.3f}")

#結果の表示
results[0].show()

結果

ノートpcの処理時間  0.689秒

デスクトップpcの処理時間  0.090 秒

一回しかやっていないので誤差ありまくりだとおもうが

約8倍差がある。