(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)
ここで、
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を読み込んでいるため人格が混ざっている感じがします。
もしかしたらベースのモデルを読み込めてないのかも。
やり方が間違っているかもしれないのでアプリケーションとして完成させるのはこの先になりそう。










