Cluster用エディター [AI搭載アイテムの作成]
상품 설명
想像以上にいいものができたので公開しました。
これの使い道は、アイテムにScriptableItemコンポーネントを追加し、
そこに入力すると実行されます。
学習データが多いほど正確にはなりますが、あまりにも多すぎると
学習しすぎてしまうため、注意してください。
少し詳しい説明は下に、実際に使う人は説明書をダウンロードすることを
お勧めします。
学習データの設定方法
最初に学習データを登録します。
列(縦)と行(横)は自由に増やせます。
一番上には項目を入れてください。
その下に情報を書いていってください。
学習データは最低でも4件以上にしてください。
学習データの例は、
気温 | 湿度 | 天気
のような感じで、気温と湿度から天気を予想するAIも作れます。
また、学習データの表をコピー、貼り付けが自由にできるので、重要なものはコピーしておくようにしておきましょう。
列の役割の設定方法
それぞれの項目で、何を入力するかをここで設定します。
まず、最初に種類を選択します。
種類は、
NumericとCategoryの二つがあります。
Numeric・・・値
Category・・・カテゴリ(文字)
役割は、
IgnoreとInputとAnswerの三つがあります。
Ignore・・・無視する
Input・・・入力
Answer・・・答え
となっています。
AIの学習の設定方法
隠れ層のサイズ・・・AIがどれだけ複雑なパターンを学習するか
学習回数・・・同じデータを何回学習するか
学習率・・・1回の学習でAIの重みをどれくらい大きく学習するか
隠れ層のサイズについて
値を大きくしすぎると丸暗記(過学習)してしまい、小さすぎるとシンプルな傾向しか覚えられない
学習回数について
値を大きくしすぎると丸暗記(過学習)してしまい、小さすぎるとパターンを覚えられない(学習不足)
学習率について
値を大きくしすぎると学習が早く進むが修正しすぎて不安定になる可能性があり、小さすぎると安定して学習が進むが時間がかかる
AIを学習させ、ClusterScriptを使ったあと
ClusterScriptが作られると、書き方が少しメモで書いてあります。例として、気温と湿度で天気がわかる機能を作ってみました。
// ================= AIモデル(Cluster AI Builderで生成したもの) =================
const AI_MODEL = {"layerSizes":[2,8,8,3],"weights":[[[-0.2599609,-0.257910043],[1.16515386,-0.493936062],[0.181739628,0.198003784],[-0.26453653,-0.0279270932],[-0.143934652,-0.009750315],[-0.09438854,-0.0366355553],[-0.169179618,-0.2868825],[-0.5433728,0.5484291]],[[-0.182949185,1.49806452,-0.2504491,-0.0941445455,-0.247677609,0.0173642188,-0.08478668,0.402760744],[0.0482986,1.82697368,0.102690168,0.123882957,-0.07648247,-0.1427711,0.111940667,-2.90929627],[0.0105304746,0.0475399457,0.00500465836,0.158717111,-0.300621271,-0.00325731887,-0.0311472658,-1.42686665],[0.126930848,-0.9459321,-0.3040232,-0.13149,0.090703316,-0.134757623,-0.0784333,3.06758642],[-0.194597527,1.88076615,0.0009773963,0.0598945,-0.0444398858,0.00436301343,-0.281900853,-0.851727962],[0.126842678,-2.32805562,0.55744195,-0.18058832,-0.2314361,-0.05249737,-0.09607375,0.01799701],[0.191799149,-0.6330142,0.193605542,0.115692049,0.15860188,-0.07958435,0.142989069,-0.672359049],[-0.03655807,-2.70302272,0.09506722,0.113591008,-0.130966812,-0.2632791,-0.2567104,1.24326587]],[[-0.315176576,3.31415987,1.07047033,-2.80730247,1.0935427,-0.4064126,0.3666346,-1.68344212],[1.23472142,-0.6360678,-1.00556922,1.73878992,0.7231264,-1.690915,-0.8021529,-1.1227479],[-1.328944,-2.46782374,-0.3079177,1.42544127,-1.76907265,1.78561068,0.2827278,2.58176327]]],"biases":[[-2.930027E-07,0.030083254,0.000105899824,-0.00269725686,0.000248215772,0.00220974954,4.062533E-05,-0.00716535142],[-0.4672233,-0.0363970846,0.15355441,-0.166457146,-0.08551705,0.299030274,-0.0280438829,0.0064746947],[-0.129627138,0.302715719,-0.173089013]],"classNames":["晴れ","曇り","雨"],"inputs":[{"name":"気温","type":"numeric"},{"name":"湿度","type":"numeric"}]};
function predictAI(features) {
let activations = features;
const layerCount = AI_MODEL.weights.length;
for (let l = 0; l < layerCount; l++) {
const isOutputLayer = (l === layerCount - 1);
const outSize = AI_MODEL.weights[l].length;
const next = new Array(outSize);
for (let o = 0; o < outSize; o++) {
let sum = AI_MODEL.biases[l][o];
const w = AI_MODEL.weights[l][o];
for (let i = 0; i < activations.length; i++) {
sum += w[i] * activations[i];
}
next[o] = isOutputLayer ? sum : (1 / (1 + Math.exp(-sum)));
}
activations = next;
}
const maxLogit = Math.max(...activations);
const exps = activations.map(v => Math.exp(v - maxLogit));
const sumExp = exps.reduce((a, b) => a + b, 0);
const probabilities = exps.map(v => v / sumExp);
let bestIndex = 0;
for (let i = 1; i < probabilities.length; i++) {
if (probabilities[i] > probabilities[bestIndex]) bestIndex = i;
}
return {
classIndex: bestIndex,
className: AI_MODEL.classNames[bestIndex],
probabilities: probabilities,
};
}
function encodeInput(rawValues) {
const features = [];
for (const col of AI_MODEL.inputs) {
const v = rawValues[col.name];
if (col.type === "numeric") {
features.push(Number(v));
} else {
for (const cat of col.categories) {
features.push(cat === v ? 1 : 0);
}
}
}
return features;
}
// ================= ここからアイテム用の処理 =================
const view = $.subNode("ResultView"); // 結果を表示するTextViewを持つSubNode
const META_TEMP = "ask_temp";
const META_HUMID = "ask_humid";
const PROMPT_TEMP = "気温は何度ですか?(数字で入力)";
const PROMPT_HUMID = "湿度は何%ですか?(数字で入力)";
// ==== 気温→湿度の順に入力を受け取る ====
$.onTextInput((text, meta, status) => {
switch (status) {
case TextInputStatus.Success:
if (meta === META_TEMP) {
$.state.temperature = text;
requestInputSafely($.state.player, META_HUMID, PROMPT_HUMID);
} else if (meta === META_HUMID) {
$.state.humidity = text;
runPrediction();
}
break;
case TextInputStatus.Busy:
$.log("入力できませんでした(Busy)");
break;
case TextInputStatus.Refused:
$.log("入力が拒否されました(Refused)");
break;
}
});
function requestInputSafely(player, meta, output) {
try {
player.requestTextInput(meta, output);
} catch (e) {
// $.log(e);
}
}
// ==== 入力が揃ったらAIで予測し、結果を表示する ====
function runPrediction() {
const inputs = encodeInput({
"気温": $.state.temperature,
"湿度": $.state.humidity,
});
const result = predictAI(inputs);
view.setText(`気温${$.state.temperature}度・湿度${$.state.humidity}%の予想天気: ${result.className}`);
$.log(`予測結果: ${result.className}(確信度: ${(result.probabilities[result.classIndex] * 100).toFixed(1)}%)`);
}
// ==== インタラクトで、気温の入力から開始する ====
$.onInteract(player => {
$.state.player = player;
requestInputSafely(player, META_TEMP, PROMPT_TEMP);
});
このような感じで使うことができます。
모든 리뷰
더보기리뷰 등록
리뷰를 작성하려면 로그인이 필요합니다.
로그인하고 리뷰 쓰기