{ "cells": [ { "id": "intro-v2", "cell_type": "markdown", "metadata": {}, "source": [ "# 日本語の問い合わせ分類を試す\n", "\n", "教材用に作成した架空の文章を使うノートブックです。XGBoostは①→②→③→④→⑥→⑨、LLMは②でRUN_LLM=Trueにして①→②→③→④→⑧→⑨を実行します。\n", "\n", "記事の数値はサーバーCPUで保存した記録です。ColabやGPUで同じ結果を確認したものではありません。\n", "\n", "LLMの実行にはPyTorchが必要です。①ではtorchをインストールしないため、入っていない環境では別途準備してください。保存時はPython 3.11.17、torch 2.8.0+cpuでした。\n", "\n", "XGBoostの記事: https://ai.technology-developer.com/notes/ai-evolution-xgboost/\n", "LLMの記事: https://ai.technology-developer.com/notes/ai-evolution-llm/\n" ] }, { "id": "guide-install", "cell_type": "markdown", "metadata": {}, "source": [ "## ① ライブラリを準備する〔install〕\n", "\n", "初回だけ実行します。完了したら②へ。ランタイム再起動を求められたら再起動後に②から進めます。\n" ] }, { "id": "install", "cell_type": "code", "metadata": {}, "source": [ "# ① ライブラリを準備する〔install〕\n", "%pip install -q numpy==2.4.6 scipy==1.16.2 scikit-learn==1.7.2 xgboost==3.1.1 transformers==4.57.6 accelerate==1.12.0\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-setup", "cell_type": "markdown", "metadata": {}, "source": [ "## ② 共通設定を読み込む〔setup〕\n", "\n", "第1〜5回はRUN_LLM=Falseのままで構いません。第6回はTrueへ変更してから、このセルを実行します。\n" ] }, { "id": "setup", "cell_type": "code", "metadata": {}, "source": [ "# ② 共通設定を読み込む〔setup〕\n", "from pathlib import Path\n", "from datetime import datetime, timezone\n", "import hashlib, json, os, platform, time, warnings, math\n", "import numpy as np\n", "import sklearn, scipy, xgboost\n", "from sklearn.feature_extraction.text import TfidfVectorizer\n", "from sklearn.linear_model import Perceptron\n", "from sklearn.neural_network import MLPClassifier\n", "from sklearn.tree import DecisionTreeClassifier\n", "from sklearn.metrics import confusion_matrix\n", "from xgboost import XGBClassifier\n", "\n", "SEED = 42\n", "RUN_LLM = False # CPUでも実行可能。待ち時間が長い場合はFalseで前半だけを試す。\n", "OUT = Path(os.environ.get('AI_TECHO_RUN_DIR', './ai-evolution-results'))\n", "OUT.mkdir(parents=True, exist_ok=True)\n", "LABELS = ['料金・請求', 'ログイン・認証', '操作・不具合']\n", "record = {'status':'running','startedAt':datetime.now(timezone.utc).isoformat(),\n", " 'location':os.environ.get('AI_TECHO_LOCATION','実行したノートブックの環境'),\n", " 'seed':SEED,'python':platform.python_version(),'platform':platform.platform(),\n", " 'versions':{'numpy':np.__version__,'scipy':scipy.__version__,\n", " 'sklearn':sklearn.__version__,'xgboost':xgboost.__version__},\n", " 'classification':[], 'labelPolicy':'現在解決したい主目的を分類。例は自作の架空文。'}\n", "def json_safe(value):\n", " \"\"\"JSONにない非有限数は、意味を失わない文字列で記録する。\"\"\"\n", " if isinstance(value, dict):\n", " return {str(k): json_safe(v) for k, v in value.items()}\n", " if isinstance(value, (list, tuple)):\n", " return [json_safe(v) for v in value]\n", " if isinstance(value, np.ndarray):\n", " return json_safe(value.tolist())\n", " if isinstance(value, np.generic):\n", " return json_safe(value.item())\n", " if isinstance(value, float) and not math.isfinite(value):\n", " return 'NaN' if math.isnan(value) else ('Infinity' if value > 0 else '-Infinity')\n", " return value\n", "\n", "def save():\n", " record['serialization'] = {'format': 'strict JSON', 'nonfiniteNumbers': 'NaN/Infinity/-Infinity strings'}\n", " payload = json.dumps(json_safe(record), ensure_ascii=False, indent=2, allow_nan=False)\n", " temporary = OUT/'results.json.tmp'\n", " temporary.write_text(payload+'\\n')\n", " temporary.replace(OUT/'results.json')\n", "print('実行場所:',record['location'])\n", "print('ライブラリ:',record['versions'])\n", "\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-dataset", "cell_type": "markdown", "metadata": {}, "source": [ "## ③ 問い合わせデータを用意する〔dataset〕\n", "\n", "学習45件、調整9件、固定比較18件を表示します。これらを作成・閲覧した経緯から、独立した未知データの評価とは扱いません。\n" ] }, { "id": "dataset", "cell_type": "code", "metadata": {}, "source": [ "# ③ 問い合わせデータを用意する〔dataset〕\n", "TRAIN = [\n", " ('月額料金はいくらですか',0),('請求額が先月より増えました',0),('支払い方法を変更したいです',0),\n", " ('領収書を発行してください',0),('無料プランの料金を確認したい',0),('カードで二重に課金されました',0),\n", " ('契約を解約して返金を希望します',0),('振込先の口座を教えてください',0),('年払いと月払いの金額を比べたい',0),\n", " ('請求書に記載する会社名を変えたい',0),('クレジットカードを登録できますか',0),('有料プランの価格を知りたい',0),\n", " ('利用料の引き落とし日を知りたい',0),('支払ったのに未払いと表示されています',0),('購入したプランをキャンセルしたい',0),\n", " ('ログインできません',1),('パスワードを忘れました',1),('認証コードが届きません',1),\n", " ('アカウントがロックされました',1),('二段階認証の設定方法を知りたい',1),('サインインすると認証に失敗します',1),\n", " ('秘密の文字列を再設定したい',1),('ログイン用のメールアドレスを変更したい',1),('IDを忘れたので確認したい',1),\n", " ('パスワードの再発行をお願いします',1),('認証アプリを新しい端末に移したい',1),('本人確認が完了しません',1),\n", " ('アカウントに入れなくなりました',1),('サインインの画面から先へ進めません',1),('ワンタイムコードが無効と言われます',1),\n", " ('画面が真っ白になります',2),('ファイルを保存できません',2),('アプリが起動しません',2),\n", " ('検索ボタンを押しても動きません',2),('データを読み込むとエラーが出ます',2),('一覧表示の文字が崩れています',2),\n", " ('CSVをアップロードできません',2),('印刷の操作方法を知りたい',2),('画像の表示がおかしいです',2),\n", " ('通知が何度も出る不具合があります',2),('検索が終わらず待ち続けています',2),('画面を開くとアプリが落ちます',2),\n", " ('ファイルのダウンロードが途中で止まります',2),('更新後にメニューを開けません',2),('動画の再生が止まります',2),\n", "]\n", "DEV = [\n", " ('料金に問題はありませんが、ログインできません',1),\n", " ('ログインはできますが、保存に失敗します',2),\n", " ('画面は正常ですが、請求額が違います',0),\n", " ('パスワードを再設定する手順を教えて',1),\n", " ('解約時のお金の扱いを知りたい',0),\n", " ('ログイン後に検索が動きません',2),\n", " ('領収書をダウンロードしたいです',0),\n", " ('新しいスマホで本人確認できません',1),\n", " ('アップロードの上限を知りたいです',2),\n", "]\n", "TEST = [\n", " ('今月の利用料について内訳を教えてください',0),\n", " ('二回お金が引き落とされているので返してほしい',0),\n", " ('ログインは問題ありませんが、請求の金額がおかしいです',0),\n", " ('保存はできるので、有料プランを解約したいです',0),\n", " ('法人名義の領収書が必要です',0),\n", " ('支払いに使うカードを別のものにしたい',0),\n", " ('自分のアカウントに入るための合言葉を忘れました',1),\n", " ('料金ではなく、サインインについて相談したいです',1),\n", " ('確認用の数字がメールに届かずアカウントに入れません',1),\n", " ('アプリは起動しますが、本人確認で拒否されます',1),\n", " ('以前の携帯をなくし二段階認証できません',1),\n", " ('ログイン時にIDが違うと言われます',1),\n", " ('ログインは成功しましたが、一覧画面が空白です',2),\n", " ('請求は正常なので、ファイルを開けない問題を解決したい',2),\n", " ('検索結果を印刷する方法を教えてください',2),\n", " ('動画を見ていると途中でアプリが終了します',2),\n", " ('アップロードした画像が横向きになります',2),\n", " ('保存ボタンを押すと反応がなくなります',2),\n", "]\n", "for split in [TRAIN,DEV,TEST]:\n", " assert set(y for _,y in split)=={0,1,2}\n", "assert len(set(x for split in [TRAIN,DEV,TEST] for x,_ in split))==sum(map(len,[TRAIN,DEV,TEST]))\n", "dataset={'train':TRAIN,'dev':DEV,'test':TEST,'labels':LABELS,\n", " 'policy':record['labelPolicy'],'authoredBy':'AI手帖の教材用に作成した架空データ','evaluationStatus':'既存の固定比較文。独立した未知データとして扱わない。'}\n", "dataset_json=json.dumps(dataset,ensure_ascii=False,indent=2)\n", "(OUT/'dataset.json').write_text(dataset_json+'\\n')\n", "record['datasetSha256']=hashlib.sha256(dataset_json.encode()).hexdigest()\n", "record['splitCounts']={k:len(v) for k,v in dataset.items() if k in ['train','dev','test']}\n", "print('固定した分割:',record['splitCounts'])\n", "\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-rules", "cell_type": "markdown", "metadata": {}, "source": [ "## ④ ルールで分類する〔rules〕\n", "\n", "旧版は「ではなく、」という比較文だけに現れる条件を含んでいました。この版は調整文に出る4条件だけを使い、調整9/9・比較14/18です。旧15/18は旧実行記録に残し、改善の一般化の根拠には使いません。\n" ] }, { "id": "rules", "cell_type": "code", "metadata": {}, "source": [ "# ④ ルールで分類する〔rules〕\n", "KEYWORDS = [\n", " ['料金','請求','支払','領収','課金','返金','解約','価格','金額','引き落と'],\n", " ['ログイン','パスワード','認証','アカウント','サインイン','本人確認','ID','コード'],\n", " ['画面','保存','ファイル','アプリ','検索','エラー','アップロード','印刷','表示','動画','ボタン'],\n", "]\n", "def rule_v1(text):\n", " for label, words in enumerate(KEYWORDS):\n", " if any(word in text for word in words): return label\n", " return -1 # 分からないものを都合よく正解にしない\n", "\n", "# 修正版: DEVに現れた条件だけを使う。既存TESTは既知の比較文であり、新しい独立評価ではない。\n", "def rule_v2(text):\n", " focus=text\n", " for marker in ['ありませんが、','できますが、','正常ですが、','後に']:\n", " if marker in focus: focus=focus.split(marker)[-1]\n", " return rule_v1(focus)\n", "\n", "def evaluate(name,predict,split=TEST,train_seconds=None,extra=None):\n", " started=time.perf_counter()\n", " predictions=[int(predict(text)) for text,_ in split]\n", " seconds=time.perf_counter()-started\n", " gold=[y for _,y in split]\n", " correct=sum(p==y for p,y in zip(predictions,gold))\n", " item={'name':name,'split':'test' if split is TEST else 'dev','correct':correct,'total':len(split),\n", " 'accuracy':correct/len(split),'invalid':sum(p not in [0,1,2] for p in predictions),\n", " 'predictionSeconds':seconds,'trainSeconds':train_seconds,\n", " 'confusionMatrix':confusion_matrix(gold,predictions,labels=[0,1,2,-1]).tolist(),\n", " 'cases':[{'text':text,'expected':y,'predicted':p,'correct':p==y} for (text,y),p in zip(split,predictions)]}\n", " if extra:item.update(extra)\n", " record['classification'].append(item);save()\n", " print(f\"{name} ({item['split']}): {correct}/{len(split)}, 形式不正・未分類 {item['invalid']}\")\n", " return item\n", "evaluate('キーワード v1',rule_v1,DEV)\n", "evaluate('調整文の条件だけのルール v2',rule_v2,DEV)\n", "evaluate('キーワード v1',rule_v1)\n", "evaluate('調整文の条件だけのルール v2',rule_v2)\n", "\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-xor", "cell_type": "markdown", "metadata": {}, "source": [ "## ⑤ XORで線形判定と多層ネットを試す〔xor〕\n", "\n", "4点に対する予測が2種類表示されます。参考実行は線形[0,0,0,0]、多層[0,1,1,0]。これは学習点への適合です。\n" ] }, { "id": "xor", "cell_type": "code", "metadata": {}, "source": [ "# ⑤ XORで線形判定と多層ネットを試す〔xor〕\n", "# XORの4点は関数の表現力を見るための全入力。未知データの評価ではない。\n", "xor_x = np.array([[0,0],[0,1],[1,0],[1,1]],dtype=float)\n", "xor_y = np.array([0,1,1,0])\n", "linear = Perceptron(max_iter=1000,tol=None,random_state=SEED,shuffle=False)\n", "linear.fit(xor_x,xor_y)\n", "nonlinear = MLPClassifier(hidden_layer_sizes=(8,),activation='tanh',solver='lbfgs',\n", " max_iter=2000,random_state=SEED,tol=1e-8,alpha=0.0001)\n", "nonlinear.fit(xor_x,xor_y)\n", "record['xor']={'inputs':xor_x.astype(int).tolist(),'expected':xor_y.tolist(),\n", " 'perceptron':linear.predict(xor_x).tolist(),\n", " 'mlp':nonlinear.predict(xor_x).tolist(),\n", " 'note':'4点そのものに適合した結果。汎化性能の比較ではない。'}\n", "print(json.dumps(record['xor'],ensure_ascii=False,indent=2))\n", "save()\n", "\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-supervised", "cell_type": "markdown", "metadata": {}, "source": [ "## ⑥ 文字TF-IDFと学習する分類器を試す〔supervised〕\n", "\n", "③と④を先に実行してください。文字TF-IDFの語彙はTRAINからだけ作り、TESTはtransformで変換します。\n" ] }, { "id": "supervised", "cell_type": "code", "metadata": {}, "source": [ "# ⑥ 文字TF-IDFと学習する分類器を試す〔supervised〕\n", "train_text=[x for x,_ in TRAIN]; train_y=np.array([y for _,y in TRAIN])\n", "# 語彙・IDFの計算はTRAINだけ。DEV・TESTにfitしない。\n", "vectorizer=TfidfVectorizer(analyzer='char',ngram_range=(1,3),min_df=1)\n", "train_x=vectorizer.fit_transform(train_text)\n", "record['features']={'analyzer':'char','ngramRange':[1,3],'vocabulary':len(vectorizer.vocabulary_),\n", " 'fitSplit':'train'}\n", "models=[\n", " ('パーセプトロン',Perceptron(max_iter=1000,tol=1e-4,random_state=SEED)),\n", " ('多層ネット(MLP)',MLPClassifier(hidden_layer_sizes=(24,),activation='tanh',solver='lbfgs',\n", " max_iter=1000,random_state=SEED,alpha=0.01)),\n", " ('決定木',DecisionTreeClassifier(max_depth=6,random_state=SEED)),\n", " ('XGBoost(45例)',XGBClassifier(n_estimators=80,max_depth=3,learning_rate=0.15,\n", " objective='multi:softprob',eval_metric='mlogloss',\n", " tree_method='hist',n_jobs=2,random_state=SEED)),\n", "]\n", "record['modelParameters']={name:obj.get_params() for name,obj in models}\n", "for name,obj in models:\n", " start=time.perf_counter();obj.fit(train_x,train_y);training=time.perf_counter()-start\n", " evaluate(name,lambda text:obj.predict(vectorizer.transform([text]))[0],train_seconds=training)\n", "\n", "# 小さい学習集合も各分類3例。特徴量もその9例だけから作る。\n", "small_indices=[0,1,2,15,16,17,30,31,32]\n", "small_vec=TfidfVectorizer(analyzer='char',ngram_range=(1,3),min_df=1)\n", "small_x=small_vec.fit_transform([TRAIN[i][0] for i in small_indices])\n", "small_y=np.array([TRAIN[i][1] for i in small_indices])\n", "small_model=XGBClassifier(n_estimators=80,max_depth=3,learning_rate=0.15,\n", " objective='multi:softprob',eval_metric='mlogloss',\n", " tree_method='hist',n_jobs=2,random_state=SEED)\n", "start=time.perf_counter();small_model.fit(small_x,small_y);training=time.perf_counter()-start\n", "evaluate('XGBoost(9例)',lambda text:small_model.predict(small_vec.transform([text]))[0],\n", " train_seconds=training,extra={'trainIndices':small_indices,'vocabulary':len(small_vec.vocabulary_)})\n", "record['smallModelParameters']=small_model.get_params();save()\n", "\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-attention", "cell_type": "markdown", "metadata": {}, "source": [ "## ⑦ Attentionの計算を追う〔attention〕\n", "\n", "Q・K・Vは人が作った値です。weightsの各行和が1であることを確認します。LLM内部の測定ではありません。\n" ] }, { "id": "attention", "cell_type": "code", "metadata": {}, "source": [ "# ⑦ Attentionの計算を追う〔attention〕\n", "# 数式を追うために人が設定したQ,K,V。学習したLLM内部の値ではない。\n", "q=np.array([[1.,0.],[0.,1.],[1.,1.]])\n", "k=q.copy();v=np.array([[1.,0.],[0.,1.],[1.,1.]])\n", "scores=q@k.T/np.sqrt(2)\n", "weights=np.exp(scores-scores.max(axis=1,keepdims=True))\n", "weights=weights/weights.sum(axis=1,keepdims=True)\n", "mixed=weights@v\n", "record['attention']={'Q':q.tolist(),'K':k.tolist(),'V':v.tolist(),\n", " 'weights':weights.tolist(),'output':mixed.tolist(),\n", " 'note':'数式の教材。学習済みLLMのattentionを測ったものではない。'}\n", "assert np.allclose(weights.sum(axis=1),1)\n", "print('Attentionの重み(各行の合計は1):\\n',np.round(weights,3))\n", "print('重み付き平均で作る出力:\\n',np.round(mixed,3));save()\n", "\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-llm", "cell_type": "markdown", "metadata": {}, "source": [ "## ⑧ Qwen3-0.6Bに分類を指示する〔llm〕\n", "\n", "②でRUN_LLM=True、③と④を実行してから進めます。初回に約1.5GBを取得します。数字の出力と各条件18件の記録が保存されます。CPUは待ち時間が長く、無料ColabのGPUや稼働時間は保証されません。\n" ] }, { "id": "llm", "cell_type": "code", "metadata": {}, "source": [ "# ⑧ Qwen3-0.6Bに分類を指示する〔llm〕\n", "if RUN_LLM:\n", " import torch, transformers, accelerate\n", " from transformers import AutoTokenizer, AutoModelForCausalLM, set_seed\n", " MODEL_ID='Qwen/Qwen3-0.6B'\n", " MODEL_REVISION='c1899de289a04d12100db370d81485cdf75e47ca'\n", " device='cuda' if torch.cuda.is_available() else 'cpu'\n", " # CPUでも重みをbfloat16で保持してメモリを抑える。端末によって速度は異なる。\n", " dtype=torch.float16 if device=='cuda' else torch.bfloat16\n", " torch.set_num_threads(2)\n", " cache=os.environ.get('AI_TECHO_MODEL_CACHE',None)\n", " start=time.perf_counter()\n", " tokenizer=AutoTokenizer.from_pretrained(MODEL_ID,revision=MODEL_REVISION,token=False,\n", " trust_remote_code=False,cache_dir=cache)\n", " model=AutoModelForCausalLM.from_pretrained(MODEL_ID,revision=MODEL_REVISION,token=False,\n", " trust_remote_code=False,torch_dtype=dtype,use_safetensors=True,\n", " low_cpu_mem_usage=True,cache_dir=cache).to(device)\n", " model.eval(); assert model.config._commit_hash==MODEL_REVISION\n", " record['llm']={'id':MODEL_ID,'revision':MODEL_REVISION,'device':device,'dtype':str(dtype),\n", " 'threads':torch.get_num_threads(),'loadSeconds':time.perf_counter()-start,\n", " 'weightsRetrained':False,'enableThinking':False,'doSample':False,\n", " 'maxNewTokens':8,'promptTemplateVersion':'support-classification-v1',\n", " 'parseRule':'strip後の出力が0,1,2の1文字の場合のみ有効'}\n", " record['versions'].update(torch=torch.__version__,transformers=transformers.__version__,accelerate=accelerate.__version__)\n", " # 分類を安定して比較するためgreedy。提供元の汎用会話向けsampling推奨とは異なる。\n", " intro='問い合わせを分類してください。0=料金・請求、1=ログイン・認証、2=操作・不具合。複数の話題がある場合は、正常なことではなく、現在解決したい問題を分類してください。回答は0、1、2のいずれか1文字だけにしてください。'\n", " example_indices=[0,3,6,15,16,17,30,31,32]\n", " example_text='\\n'.join(f'例: {TRAIN[i][0]} → {TRAIN[i][1]}' for i in example_indices)\n", " for name,examples in [('LLM(例なし)',''),('LLM(9例を提示)',example_text)]:\n", " raw_cases=[]\n", " def classify(text):\n", " prompt=intro+'\\n'+examples+'\\n問い合わせ: '+text+'\\n回答:'\n", " chat=tokenizer.apply_chat_template([{'role':'user','content':prompt}],tokenize=False,\n", " add_generation_prompt=True,enable_thinking=False)\n", " inputs=tokenizer(chat,return_tensors='pt').to(device)\n", " set_seed(SEED)\n", " if device=='cuda':torch.cuda.synchronize()\n", " started=time.perf_counter()\n", " with torch.inference_mode():\n", " ids=model.generate(**inputs,max_new_tokens=8,do_sample=False,\n", " pad_token_id=tokenizer.eos_token_id)\n", " if device=='cuda':torch.cuda.synchronize()\n", " elapsed=time.perf_counter()-started\n", " out_ids=ids[0,inputs['input_ids'].shape[1]:]\n", " raw=tokenizer.decode(out_ids,skip_special_tokens=True)\n", " parsed=int(raw.strip()) if raw.strip() in ['0','1','2'] else -1\n", " raw_cases.append({'input':text,'prompt':prompt,'rawOutput':raw,'outputTokenIds':out_ids.tolist(),\n", " 'inputTokens':inputs['input_ids'].shape[1],'outputTokens':len(out_ids),\n", " 'hitTokenLimit':len(out_ids)==8,'generationSeconds':elapsed,'parsed':parsed})\n", " print(f' {name}: {len(raw_cases)}/{len(TEST)}',flush=True)\n", " return parsed\n", " result=evaluate(name,classify,extra={'exampleTrainIndices':example_indices if examples else []})\n", " result['rawCases']=raw_cases;save()\n", "else:\n", " record['llm']={'status':'skipped','reason':'RUN_LLM=False'}\n", " print('LLM未実行。第6回は②でRUN_LLM=Trueにし、②→③→④→⑧→⑨を実行します。')\n", "\n" ], "execution_count": null, "outputs": [] }, { "id": "guide-report", "cell_type": "markdown", "metadata": {}, "source": [ "## ⑨ 記録を保存して確かめる〔report〕\n", "\n", "完了時にresults.jsonとcomparison.csvを保存します。JSONはNaNを裸の数値で含めない形式です。LLMを無効にした場合、その未実行状態も記録します。\n" ] }, { "id": "report", "cell_type": "code", "metadata": {}, "source": [ "# ⑨ 記録を保存して確かめる〔report〕\n", "record['status']='completed';record['finishedAt']=datetime.now(timezone.utc).isoformat();save()\n", "lines=['モデル,正解数,件数,未分類・形式不正,推論秒']\n", "for r in record['classification']:\n", " if r['split']=='test':\n", " lines.append(f\"{r['name']},{r['correct']},{r['total']},{r['invalid']},{r['predictionSeconds']:.4f}\")\n", "(OUT/'comparison.csv').write_text('\\n'.join(lines)+'\\n')\n", "print('\\n'.join(lines))\n", "print('結果保存先:',OUT)\n", "print('小さな架空データの単回実験です。一般的な優劣や業務精度を示しません。')\n" ], "execution_count": null, "outputs": [] }, { "id": "references-v2", "cell_type": "markdown", "metadata": {}, "source": [ "## 参照資料\n", "\n", "- [Turing(1950)](https://academic.oup.com/mind/article/LIX/236/433/986238)\n", "- [ダートマス提案(1955)](https://www-formal.stanford.edu/jmc/history/dartmouth/dartmouth.html)\n", "- [誤差逆伝播(1986)](https://www.cs.toronto.edu/~hinton/absps/naturebp.pdf)\n", "- [AlexNet(2012)](https://www.cs.toronto.edu/~kriz/imagenet_classification_with_deep_convolutional.pdf)\n", "- [XGBoost(2016)](https://arxiv.org/abs/1603.02754)\n", "- [Transformer(2017)、3.2.1](https://arxiv.org/html/1706.03762v7#S3.SS2.SSS1)\n", "- [Qwen3-0.6B](https://huggingface.co/Qwen/Qwen3-0.6B)\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python" }, "colab": { "name": "ai-evolution-lab-v2-20261012.ipynb" }, "aiTecho": { "version": 2, "changedAt": "2026-10-12", "changes": [ "visible numbered headings", "DEV-supported rule conditions", "strict JSON save" ], "originalNotebookSha256": "94285be83f1614492f323a8343d9dda0bf4d17600b7108f3c2f1314f17bac305", "llmDefault": "disabled" } }, "nbformat": 4, "nbformat_minor": 5 }