Pyodide里的Tensorflow目录
可以跑通基本的训练、使用模型过程
This commit is contained in:
230
boards/default_src/python_pyodide/blocks/tensorflow.js
Normal file
230
boards/default_src/python_pyodide/blocks/tensorflow.js
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
|
const TENSORFLOW_HUE = '#1216ab';
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_init_tensor = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("VAR")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_INIT_TENSOR);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_sequential = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_SEQUENTIAL);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_layers_dense = {
|
||||||
|
init: function () {
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_INIT_LAYERS_DENSE_LAYER);
|
||||||
|
this.appendValueInput("VAR1")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_OUTPUT_DIMENSION);
|
||||||
|
this.appendValueInput("VAR2")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_INPUT_SHAPE);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_add = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("VAR1")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_MODEL);
|
||||||
|
this.appendValueInput("VAR2")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_ADD_LAYER);
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_compile = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("VAR1")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_COMPILE_MODEL);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_LOSS_FUNCTION_TYPE)
|
||||||
|
.appendField(new Blockly.FieldDropdown([
|
||||||
|
[Blockly.Msg.MIXLY_TENSORFLOW_MEAN_SQUARED_ERROR, "meanSquaredError"]
|
||||||
|
]), "VAR2");
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_OPTIMIZER)
|
||||||
|
.appendField(new Blockly.FieldDropdown([
|
||||||
|
[Blockly.Msg.MIXLY_TENSORFLOW_SGD, "sgd"]
|
||||||
|
]), "VAR3");
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_fit = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("VAR1")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_FIT_MODEL);
|
||||||
|
this.appendValueInput("VAR2")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_FIT_INPUT_DATA);
|
||||||
|
this.appendValueInput("VAR3")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_FIT_TARGET_DATA);
|
||||||
|
this.appendValueInput("VAR4")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_FIT_EPOCHS);
|
||||||
|
this.appendValueInput("VAR5")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_FIT_VERBOSE);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_FIT_RETURN_HISTORY);
|
||||||
|
this.setInputsInline(false);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_get_loss = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("VAR")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY_2);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_predict = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("VAR1")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_PREDICT);
|
||||||
|
this.appendValueInput("VAR2")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_PREDICT_INPUT_DATA);
|
||||||
|
this.appendDummyInput()
|
||||||
|
.setAlign(Blockly.ALIGN_RIGHT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_PREDICT_RETURN_RESULT);
|
||||||
|
this.setInputsInline(false);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_get_tensor_data = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("VAR")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_GET_TENSOR_DATA);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_save_or_export_model = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("NAME1")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_MODEL);
|
||||||
|
this.appendValueInput("NAME2")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(new Blockly.FieldDropdown([
|
||||||
|
[Blockly.Msg.MIXLY_TENSORFLOW_SAVE_MODEL, "save"],
|
||||||
|
[Blockly.Msg.MIXLY_TENSORFLOW_EXPORT_MODEL, "export"]
|
||||||
|
]), "NAME")
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_SAVE_MODEL_NAME);
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setPreviousStatement(true, null);
|
||||||
|
this.setNextStatement(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_use_load_model = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("NAME")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_LOAD_MODEL)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_MODEL_NAME);
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Blockly.Blocks.tensorflow_prepare_picture = {
|
||||||
|
init: function () {
|
||||||
|
this.appendValueInput("NAME")
|
||||||
|
.setCheck(null)
|
||||||
|
.setAlign(Blockly.ALIGN_LEFT)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_PREPARE_PICTURE_TO_TENSOR)
|
||||||
|
.appendField(Blockly.Msg.MIXLY_TENSORFLOW_PREPARE_PICTURE_READ_PICTURE);
|
||||||
|
this.setInputsInline(true);
|
||||||
|
this.setOutput(true, null);
|
||||||
|
this.setColour(TENSORFLOW_HUE);
|
||||||
|
this.setTooltip('');
|
||||||
|
this.setHelpUrl('');
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
import * as PythonPyodideSKLearnBlocks from './blocks/sklearn';
|
import * as PythonPyodideSKLearnBlocks from './blocks/sklearn';
|
||||||
import * as PythonPyodideSKLearnGenerators from './generators/sklearn';
|
import * as PythonPyodideSKLearnGenerators from './generators/sklearn';
|
||||||
|
import * as PythonTensorflowBlocks from './blocks/tensorflow';
|
||||||
|
import * as PythonTensorflowGenerators from './generators/tensorflow';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
PythonPyodideSKLearnBlocks,
|
PythonPyodideSKLearnBlocks,
|
||||||
PythonPyodideSKLearnGenerators
|
PythonPyodideSKLearnGenerators,
|
||||||
|
PythonTensorflowBlocks,
|
||||||
|
PythonTensorflowGenerators
|
||||||
};
|
};
|
||||||
97
boards/default_src/python_pyodide/generators/tensorflow.js
Normal file
97
boards/default_src/python_pyodide/generators/tensorflow.js
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
export const tensorflow_init_tensor = function (_, generator) {
|
||||||
|
var VALUE_INPUT_VAR = generator.valueToCode(this, "VAR", generator.ORDER_ATOMIC);
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var code = 'tensorflow.tensor(' + VALUE_INPUT_VAR + ')';
|
||||||
|
return [code, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_sequential = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var code = 'tensorflow.sequential()';
|
||||||
|
return [code, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_layers_dense = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var VALUE_INPUT_VAR1 = generator.valueToCode(this, "VAR1", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR2 = generator.valueToCode(this, "VAR2", generator.ORDER_ATOMIC);
|
||||||
|
var code = 'tensorflow.layers.dense(units = ' + VALUE_INPUT_VAR1 + ', input_shape = ' + VALUE_INPUT_VAR2 + ')';
|
||||||
|
return [code, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_add = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var VALUE_INPUT_VAR1 = generator.valueToCode(this, "VAR1", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR2 = generator.valueToCode(this, "VAR2", generator.ORDER_ATOMIC);
|
||||||
|
var code = VALUE_INPUT_VAR1 + '.add(' + VALUE_INPUT_VAR2 + ')\n';
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_compile = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var VALUE_INPUT_VAR1 = generator.valueToCode(this, "VAR1", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR2 = this.getFieldValue("VAR2");
|
||||||
|
var VALUE_INPUT_VAR3 = this.getFieldValue("VAR3");
|
||||||
|
var code = VALUE_INPUT_VAR1 + '.compile(loss = "' + VALUE_INPUT_VAR2 + '", optimizer = "' + VALUE_INPUT_VAR3 + '")\n';
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const tensorflow_fit = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var VALUE_INPUT_VAR1 = generator.valueToCode(this, "VAR1", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR2 = generator.valueToCode(this, "VAR2", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR3 = generator.valueToCode(this, "VAR3", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR4 = generator.valueToCode(this, "VAR4", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR5 = generator.valueToCode(this, "VAR5", generator.ORDER_ATOMIC);
|
||||||
|
var code = 'await ' + VALUE_INPUT_VAR1 + '.fit(' + VALUE_INPUT_VAR2 + ', ' + VALUE_INPUT_VAR3 + ', epochs=' + VALUE_INPUT_VAR4 + ', verbose=' + VALUE_INPUT_VAR5 + ')';
|
||||||
|
return [code, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_get_loss = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var VALUE_INPUT_VAR = generator.valueToCode(this, "VAR", generator.ORDER_ATOMIC);
|
||||||
|
var code = VALUE_INPUT_VAR + '.history.loss';
|
||||||
|
return [code, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_predict = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var VALUE_INPUT_VAR1 = generator.valueToCode(this, "VAR1", generator.ORDER_ATOMIC);
|
||||||
|
var VALUE_INPUT_VAR2 = generator.valueToCode(this, "VAR2", generator.ORDER_ATOMIC);
|
||||||
|
var code = VALUE_INPUT_VAR1 + '.predict(' + VALUE_INPUT_VAR2 + ')';
|
||||||
|
return [code, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_get_tensor_data = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
var VALUE_INPUT_VAR1 = generator.valueToCode(this, "VAR", generator.ORDER_ATOMIC);
|
||||||
|
var code = "(await " + VALUE_INPUT_VAR1 + ".data())";
|
||||||
|
return [code, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_save_or_export_model = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
|
||||||
|
var VALUE_INPUT_NAME1 = generator.valueToCode(this, "NAME1", generator.ORDER_ATOMIC);
|
||||||
|
var FIELD_NAME = this.getFieldValue("NAME");
|
||||||
|
var VALUE_INPUT_NAME2 = generator.valueToCode(this, "NAME2", generator.ORDER_ATOMIC).replace(/^'|'$/g, '');
|
||||||
|
if (FIELD_NAME == "export") {
|
||||||
|
return `await ${VALUE_INPUT_NAME1}.save("downloads://${VALUE_INPUT_NAME2}")\n`;
|
||||||
|
}
|
||||||
|
return `await ${VALUE_INPUT_NAME1}.save("indexeddb://${VALUE_INPUT_NAME2}")\n`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_use_load_model = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
|
||||||
|
var VALUE_INPUT_NAME = generator.valueToCode(this, "NAME", generator.ORDER_ATOMIC).replace(/^'|'$/g, '');
|
||||||
|
return [`await tensorflow.load_model("${VALUE_INPUT_NAME}")`, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tensorflow_prepare_picture = function (_, generator) {
|
||||||
|
generator.definitions_['import_tensorflow'] = 'import tensorflow';
|
||||||
|
generator.definitions_['import_numpy'] = 'import numpy';
|
||||||
|
generator.definitions_['import_PIL'] = 'import PIL';
|
||||||
|
var VALUE_INPUT_NAME = generator.valueToCode(this, "NAME", generator.ORDER_ATOMIC);
|
||||||
|
return [`(await tensorflow.prepare_qmyixtxi(tensorflow.tensor(numpy.array(PIL.Image.open(${VALUE_INPUT_NAME}).convert('RGB')))))`, generator.ORDER_ATOMIC];
|
||||||
|
};
|
||||||
@@ -69,7 +69,9 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
PythonPyodideSKLearnBlocks,
|
PythonPyodideSKLearnBlocks,
|
||||||
PythonPyodideSKLearnGenerators
|
PythonPyodideSKLearnGenerators,
|
||||||
|
PythonTensorflowBlocks,
|
||||||
|
PythonTensorflowGenerators
|
||||||
} from './';
|
} from './';
|
||||||
|
|
||||||
import './others/loader';
|
import './others/loader';
|
||||||
@@ -113,7 +115,8 @@ Object.assign(
|
|||||||
PythonMixpySKLearnBlocks,
|
PythonMixpySKLearnBlocks,
|
||||||
PythonMixpySystemBlocks,
|
PythonMixpySystemBlocks,
|
||||||
PythonMixpyTurtleBlocks,
|
PythonMixpyTurtleBlocks,
|
||||||
PythonPyodideSKLearnBlocks
|
PythonPyodideSKLearnBlocks,
|
||||||
|
PythonTensorflowBlocks
|
||||||
);
|
);
|
||||||
|
|
||||||
Object.assign(
|
Object.assign(
|
||||||
@@ -146,5 +149,6 @@ Object.assign(
|
|||||||
PythonMixpySKLearnGenerators,
|
PythonMixpySKLearnGenerators,
|
||||||
PythonMixpySystemGenerators,
|
PythonMixpySystemGenerators,
|
||||||
PythonMixpyTurtleGenerators,
|
PythonMixpyTurtleGenerators,
|
||||||
PythonPyodideSKLearnGenerators
|
PythonPyodideSKLearnGenerators,
|
||||||
|
PythonTensorflowGenerators
|
||||||
);
|
);
|
||||||
Binary file not shown.
@@ -3378,6 +3378,17 @@
|
|||||||
"sprite"
|
"sprite"
|
||||||
],
|
],
|
||||||
"depends": []
|
"depends": []
|
||||||
|
},
|
||||||
|
"tensorflow": {
|
||||||
|
"name": "tensorflow",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"file_name": "{basthonRoot}/modules/tensorflow-0.0.1-py3-none-any.whl",
|
||||||
|
"install_dir": "site",
|
||||||
|
"sha256": "734415520a240e19f44c6121f0e237300c9f82ce87635a9e40a6639d0f35c888",
|
||||||
|
"imports": [
|
||||||
|
"tensorflow"
|
||||||
|
],
|
||||||
|
"depends": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,328 @@ import NavExt from './nav-ext';
|
|||||||
import * as tf from '@tensorflow/tfjs';
|
import * as tf from '@tensorflow/tfjs';
|
||||||
import './tensorflow';
|
import './tensorflow';
|
||||||
|
|
||||||
|
import * as Blockly from 'blockly/core';
|
||||||
NavExt.init();
|
NavExt.init();
|
||||||
window.tf = tf;
|
window.tf = tf;
|
||||||
|
|
||||||
|
let featureExtractor;
|
||||||
|
// featureExtractor = await tf.loadGraphModel("../common/media/tfmodel/model.json");
|
||||||
|
// window.featureExtractor = featureExtractor;
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
document.getElementById('modalOverlay').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从IndexedDB删除单个模型
|
||||||
|
async function deleteModel(modelName) {
|
||||||
|
try {
|
||||||
|
await tf.io.removeModel(`indexeddb://${modelName}`);
|
||||||
|
// 从UI移除
|
||||||
|
const modelItem = document.querySelector(`.model-item[data-model-name="${modelName}"]`);
|
||||||
|
if (modelItem) modelItem.remove();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除模型失败:', error);
|
||||||
|
alert('删除模型失败: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示单个模型项
|
||||||
|
function displayModelItem(modelName) {
|
||||||
|
const modelsList = document.getElementById('imported-models');
|
||||||
|
if ([...modelsList.children].some(item => item.dataset.modelName === modelName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const modelItem = document.createElement('div');
|
||||||
|
modelItem.className = 'model-item';
|
||||||
|
modelItem.dataset.modelName = modelName;
|
||||||
|
modelItem.innerHTML = `
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; padding: 8px 10px; border-bottom: 1px solid #eee;">
|
||||||
|
<span style="font-size: 1em; color: #333;">${modelName}</span>
|
||||||
|
<button class="delete-model" style="
|
||||||
|
background: #f44336;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9em;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
">删除</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 绑定删除事件
|
||||||
|
modelItem.querySelector('.delete-model').addEventListener('click', () => {
|
||||||
|
deleteModel(modelName);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelsList.appendChild(modelItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空所有模型
|
||||||
|
async function clearAllModels() {
|
||||||
|
try {
|
||||||
|
const modelInfos = await tf.io.listModels();
|
||||||
|
const deletePromises = Object.keys(modelInfos)
|
||||||
|
.map(path => path.replace('indexeddb://', ''))
|
||||||
|
.map(modelName => tf.io.removeModel(`indexeddb://${modelName}`));
|
||||||
|
|
||||||
|
await Promise.all(deletePromises);
|
||||||
|
document.getElementById('imported-models').innerHTML = '';
|
||||||
|
} catch (error) {
|
||||||
|
console.error('清空模型失败:', error);
|
||||||
|
alert('清空模型失败: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载并显示所有模型
|
||||||
|
async function loadAndDisplayAllModels() {
|
||||||
|
try {
|
||||||
|
const modelInfos = await tf.io.listModels();
|
||||||
|
document.getElementById('imported-models').innerHTML = '';
|
||||||
|
for (const [path] of Object.entries(modelInfos)) {
|
||||||
|
const modelName = path.replace('indexeddb://', '');
|
||||||
|
displayModelItem(modelName);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载模型列表失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createModal() {
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.id = 'modalOverlay';
|
||||||
|
Object.assign(overlay.style, {
|
||||||
|
display: 'none',
|
||||||
|
position: 'fixed',
|
||||||
|
top: '0',
|
||||||
|
left: '0',
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||||
|
zIndex: '20011216',
|
||||||
|
pointerEvents: 'auto'
|
||||||
|
});
|
||||||
|
const content = document.createElement('div');
|
||||||
|
Object.assign(content.style, {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
width: '60%',
|
||||||
|
maxHeight: '80%',
|
||||||
|
margin: '12vh auto',
|
||||||
|
padding: '20px 30px',
|
||||||
|
borderRadius: '12px'
|
||||||
|
});
|
||||||
|
content.innerHTML = `
|
||||||
|
<h2 style="margin-bottom: 20px;">选择本地模型</h2>
|
||||||
|
<div style="margin-bottom: 25px; position: relative; min-height: 200px;"> <!-- 新增 min-height 和 position -->
|
||||||
|
<input type="file" id="model-upload" accept=".json,.bin" multiple style="display: none;">
|
||||||
|
<label for="model-upload" style="
|
||||||
|
background: #1216ab;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
">选择模型文件</label>
|
||||||
|
<div style="display: flex; gap: 10px; margin-top: 15px; align-items: center;">
|
||||||
|
<span style="line-height: 36px;">导入模型名称:</span>
|
||||||
|
<input type="text" id="model-name" placeholder="模型名称" value="my-model" style="
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
flex: 1;
|
||||||
|
max-width: 200px;
|
||||||
|
">
|
||||||
|
<button id="model-handle" style="
|
||||||
|
background: #1216ab;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
">保存模型</button>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 15px; display: flex; gap: 20px;">
|
||||||
|
<div id="json-status" style="
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
flex: 1;
|
||||||
|
">
|
||||||
|
<span>❌ 模型结构描述文件(model.json)</span>
|
||||||
|
|
||||||
|
<div style="color: #666; font-size: 0.9em; margin-top: 5px;">未选择</div>
|
||||||
|
</div>
|
||||||
|
<div id="weights-status" style="
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
flex: 1;
|
||||||
|
">
|
||||||
|
<span>❌ 权重文件(model.weights.bin)</span>
|
||||||
|
<div style="color: #666; font-size: 0.9em; margin-top: 5px;">0 个已选择</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="output" style="margin-bottom: 15px; min-height: 40px;"></div>
|
||||||
|
<div style="margin-top: 20px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||||
|
<h3>已导入模型</h3>
|
||||||
|
<div style="display: flex; gap: 10px;">
|
||||||
|
<button id="refresh-models" style="
|
||||||
|
background: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
">刷新</button>
|
||||||
|
<button id="clear-models" style="
|
||||||
|
background: #f44336;
|
||||||
|
color: white;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
">清空</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="imported-models" style="
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
">
|
||||||
|
<div style="color: #666; font-style: italic;">加载中...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: flex-end; margin-top: 15px;">
|
||||||
|
<button class="close-btn" style="
|
||||||
|
background: #e0e0e0;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
">关闭</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
overlay.appendChild(content);
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
|
||||||
|
content.querySelector('.close-btn').addEventListener('click', closeModal);
|
||||||
|
overlay.addEventListener('click', (e) => {
|
||||||
|
if (e.target === overlay) closeModal();
|
||||||
|
});
|
||||||
|
// 获取DOM元素
|
||||||
|
const modelUpload = document.getElementById('model-upload');
|
||||||
|
const modelHandle = document.getElementById('model-handle');
|
||||||
|
const outputDiv = document.getElementById('output');
|
||||||
|
|
||||||
|
let jsonFile = null;
|
||||||
|
let weightFiles = [];
|
||||||
|
|
||||||
|
modelUpload.addEventListener('change', async (event) => {
|
||||||
|
const files = event.target.files;
|
||||||
|
|
||||||
|
// 获取状态元素
|
||||||
|
const jsonStatus = document.getElementById('json-status');
|
||||||
|
const weightsStatus = document.getElementById('weights-status');
|
||||||
|
|
||||||
|
// 重置状态显示(保持完整文件名描述)
|
||||||
|
jsonStatus.querySelector('span').textContent = '❌ 模型结构描述文件(model.json)';
|
||||||
|
jsonStatus.querySelector('div').textContent = '未选择';
|
||||||
|
weightsStatus.querySelector('span').textContent = '❌ 权重文件(model.weights.bin)';
|
||||||
|
weightsStatus.querySelector('div').textContent = '0 个已选择';
|
||||||
|
|
||||||
|
// 分离 JSON 和权重文件
|
||||||
|
weightFiles = [];
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
if (files[i].name.endsWith('.json')) {
|
||||||
|
jsonFile = files[i];
|
||||||
|
} else {
|
||||||
|
weightFiles.push(files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jsonFile) {
|
||||||
|
alert('未找到 model.json 文件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputDiv.innerHTML = '正在处理上传的模型文件...';
|
||||||
|
|
||||||
|
if (jsonFile) {
|
||||||
|
jsonStatus.querySelector('span').textContent = '✅ 模型结构描述文件(model.json)';
|
||||||
|
jsonStatus.querySelector('div').textContent = '已选择';
|
||||||
|
const modelName = jsonFile.name.replace('.json', '');
|
||||||
|
document.getElementById('model-name').value = modelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weightFiles.length > 0) {
|
||||||
|
weightsStatus.querySelector('span').textContent = '✅ 权重文件(model.weights.bin)';
|
||||||
|
weightsStatus.querySelector('div').textContent = `${weightFiles.length} 个已选择`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
modelHandle.addEventListener('click', async () => {
|
||||||
|
try {
|
||||||
|
const modelNameInput = document.getElementById('model-name');
|
||||||
|
const modelName = modelNameInput.value || 'mixly-model';
|
||||||
|
|
||||||
|
const model = await tf.loadLayersModel(
|
||||||
|
tf.io.browserFiles([jsonFile, ...weightFiles])
|
||||||
|
);
|
||||||
|
await model.save(`indexeddb://${modelName}`);
|
||||||
|
loadAndDisplayAllModels();
|
||||||
|
outputDiv.innerHTML = `模型已成功保存为 ${modelName}!`;
|
||||||
|
} catch (error) {
|
||||||
|
outputDiv.innerHTML = `保存模型出错: ${error.message}`;
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
content.querySelector('#refresh-models').addEventListener('click', loadAndDisplayAllModels);
|
||||||
|
content.querySelector('#clear-models').addEventListener('click', async () => {
|
||||||
|
if (confirm('确定要删除所有模型吗?此操作不可恢复!')) {
|
||||||
|
await clearAllModels();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createModal();
|
||||||
|
|
||||||
|
await loadAndDisplayAllModels();
|
||||||
|
|
||||||
|
function openModal() {
|
||||||
|
loadAndDisplayAllModels();
|
||||||
|
document.getElementById('modalOverlay').style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspace = Blockly.getMainWorkspace();
|
||||||
|
workspace.registerButtonCallback('handleModels', function () {
|
||||||
|
openModal();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
async function prepare_qmyixtxi(imgTensor) {
|
||||||
|
let net = null;
|
||||||
|
|
||||||
|
if (window.featureExtractor) {
|
||||||
|
net = window.featureExtractor;
|
||||||
|
} else {
|
||||||
|
net = await tf.loadGraphModel("../common/media/tfmodel/model.json");
|
||||||
|
window.featureExtractor = net;
|
||||||
|
}
|
||||||
|
const preprocessedImg = imgTensor
|
||||||
|
.resizeBilinear([224, 224])
|
||||||
|
.toFloat()
|
||||||
|
.div(tf.scalar(127.5))
|
||||||
|
.sub(tf.scalar(1))
|
||||||
|
.expandDims(0);
|
||||||
|
|
||||||
|
const features = featureExtractor.predict(preprocessedImg);
|
||||||
|
|
||||||
|
let activation = features;
|
||||||
|
return activation;
|
||||||
|
}
|
||||||
|
window.prepare_qmyixtxi = prepare_qmyixtxi;
|
||||||
|
|||||||
@@ -8,31 +8,6 @@ import teachableModel from './components/teachableModel.vue';
|
|||||||
// import 'element-plus/theme-chalk/el-notification.css';
|
// import 'element-plus/theme-chalk/el-notification.css';
|
||||||
// import './styles/index.scss';
|
// import './styles/index.scss';
|
||||||
|
|
||||||
|
|
||||||
const userInfo = reactive({
|
|
||||||
is_Login: false,
|
|
||||||
username: '',
|
|
||||||
password: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
const apiurl = ref('http://127.0.0.1:5174')
|
|
||||||
provide('apiurl', apiurl.value)
|
|
||||||
|
|
||||||
provide('userInfo', userInfo)
|
|
||||||
onMounted(() => {
|
|
||||||
// 获取当前的LS里的已经登录的信息
|
|
||||||
if (
|
|
||||||
localStorage.getItem('myAIplatformUsername')
|
|
||||||
&& localStorage.getItem('myAIplatformPassword')
|
|
||||||
) {
|
|
||||||
userInfo.is_Login = true
|
|
||||||
userInfo.username = localStorage.getItem('myAIplatformUsername')
|
|
||||||
userInfo.password = localStorage.getItem('myAIplatformPassword')
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
userInfo.is_Login = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
// import * as mobilenet from "@tensorflow-models/mobilenet";
|
// import * as mobilenet from "@tensorflow-models/mobilenet";
|
||||||
import * as tf from '@tensorflow/tfjs';
|
import * as tf from "@tensorflow/tfjs";
|
||||||
import * as tfvis from '@tensorflow/tfjs-vis';
|
import * as tfvis from "@tensorflow/tfjs-vis";
|
||||||
import * as path from 'path';
|
import * as path from "path";
|
||||||
import { inject, ref } from 'vue';
|
import { inject, ref } from "vue";
|
||||||
import { ElMessage, ElButton, ElCard, ElRow, ElCol, ElInput, ElProgress, ElUpload } from 'element-plus';
|
import {
|
||||||
import { Env } from 'mixly';
|
ElMessage,
|
||||||
|
ElButton,
|
||||||
|
ElCard,
|
||||||
|
ElRow,
|
||||||
|
ElCol,
|
||||||
|
ElInput,
|
||||||
|
ElProgress,
|
||||||
|
ElUpload,
|
||||||
|
} from "element-plus";
|
||||||
|
import { Env } from "mixly";
|
||||||
|
|
||||||
// import 'element-plus/theme-chalk/el-message.css';
|
// import 'element-plus/theme-chalk/el-message.css';
|
||||||
// import 'element-plus/theme-chalk/el-button.css';
|
// import 'element-plus/theme-chalk/el-button.css';
|
||||||
@@ -16,86 +25,84 @@ import { Env } from 'mixly';
|
|||||||
// import 'element-plus/theme-chalk/el-progress.css';
|
// import 'element-plus/theme-chalk/el-progress.css';
|
||||||
// import 'element-plus/theme-chalk/el-upload.css';
|
// import 'element-plus/theme-chalk/el-upload.css';
|
||||||
|
|
||||||
|
const emit = defineEmits(["shot"]);
|
||||||
const emit = defineEmits(['shot'])
|
|
||||||
// 类别及其样本的列表
|
// 类别及其样本的列表
|
||||||
const picList = inject('picList')
|
const picList = inject("picList");
|
||||||
// 图片列表
|
// 图片列表
|
||||||
const shotList = inject('shotList')
|
const shotList = inject("shotList");
|
||||||
// 训练状态
|
// 训练状态
|
||||||
const states = inject('states')
|
const states = inject("states");
|
||||||
|
|
||||||
// 用来显示进度条和名称
|
// 用来显示进度条和名称
|
||||||
const classList = ref(
|
const classList = ref(
|
||||||
picList.value.map((item, idx) => ({
|
picList.value.map((item, idx) => ({
|
||||||
name: item.title,
|
name: item.title,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
})),
|
}))
|
||||||
)
|
);
|
||||||
const progressColors = ['#FF6F61', '#42A5F5', '#66BB6A', '#FFA726', '#AB47BC']
|
const progressColors = ["#FF6F61", "#42A5F5", "#66BB6A", "#FFA726", "#AB47BC"];
|
||||||
// 用来存储模型
|
// 用来存储模型
|
||||||
let featureExtractor
|
let featureExtractor;
|
||||||
// 用来存储损失值
|
// 用来存储损失值
|
||||||
let lossValues = []
|
let lossValues = [];
|
||||||
// 存储被训练的模型
|
// 存储被训练的模型
|
||||||
let model
|
let model;
|
||||||
|
|
||||||
// 单击训练按钮后训练模型
|
// 单击训练按钮后训练模型
|
||||||
async function train() {
|
async function train() {
|
||||||
// 可视化相关
|
// 可视化相关
|
||||||
const visPanel = document.getElementById('vis-left-panel')
|
const visPanel = document.getElementById("vis-left-panel");
|
||||||
if (visPanel)
|
if (visPanel) visPanel.innerHTML = "训练准备中……";
|
||||||
visPanel.innerHTML = '训练准备中……'
|
showVisPanel.value = true;
|
||||||
showVisPanel.value = true
|
console.log("正在加载Mobilenet……");
|
||||||
console.log('正在加载Mobilenet……')
|
|
||||||
// net = await mobilenet.load();
|
// net = await mobilenet.load();
|
||||||
featureExtractor = await tf.loadGraphModel(path.join(Env.boardDirPath, 'teachableModel/model.json'))
|
featureExtractor = await tf.loadGraphModel(
|
||||||
|
path.join(Env.boardDirPath, "teachableModel/model.json")
|
||||||
|
);
|
||||||
|
|
||||||
console.log('Mobilenet加载完成。')
|
console.log("Mobilenet加载完成。");
|
||||||
if (visPanel)
|
if (visPanel) visPanel.innerHTML = "";
|
||||||
visPanel.innerHTML = ''
|
|
||||||
|
|
||||||
// 准备数据
|
// 准备数据
|
||||||
const NUM_CLASSES = picList.value.length
|
const NUM_CLASSES = picList.value.length;
|
||||||
let xs = null
|
let xs = null;
|
||||||
let ys = null
|
let ys = null;
|
||||||
// 准备模型
|
// 准备模型
|
||||||
model = tf.sequential()
|
model = tf.sequential();
|
||||||
// 添加全连接层
|
// 添加全连接层
|
||||||
model.add(
|
model.add(
|
||||||
tf.layers.dense({
|
tf.layers.dense({
|
||||||
inputShape: [1280],
|
inputShape: [1280],
|
||||||
units: 128,
|
units: 128,
|
||||||
activation: 'relu',
|
activation: "relu",
|
||||||
}),
|
})
|
||||||
)
|
);
|
||||||
// 添加分类层
|
// 添加分类层
|
||||||
model.add(
|
model.add(
|
||||||
tf.layers.dense({
|
tf.layers.dense({
|
||||||
units: NUM_CLASSES,
|
units: NUM_CLASSES,
|
||||||
activation: 'softmax',
|
activation: "softmax",
|
||||||
}),
|
})
|
||||||
)
|
);
|
||||||
// 编译模型
|
// 编译模型
|
||||||
model.compile({
|
model.compile({
|
||||||
optimizer: tf.train.adam(0.001),
|
optimizer: tf.train.adam(0.001),
|
||||||
loss: 'categoricalCrossentropy',
|
loss: "categoricalCrossentropy",
|
||||||
metrics: ['accuracy'],
|
metrics: ["accuracy"],
|
||||||
})
|
});
|
||||||
|
|
||||||
for (let classId = 0; classId < picList.value.length; classId++) {
|
for (let classId = 0; classId < picList.value.length; classId++) {
|
||||||
if (picList.value[classId].disabled)
|
if (picList.value[classId].disabled) continue;
|
||||||
continue
|
const images = picList.value[classId].list;
|
||||||
const images = picList.value[classId].list
|
|
||||||
for (let i = 0; i < images.length; i++) {
|
for (let i = 0; i < images.length; i++) {
|
||||||
// 加载图片
|
// 加载图片
|
||||||
const imgElement = new Image()
|
const imgElement = new Image();
|
||||||
imgElement.src = images[i]
|
imgElement.src = images[i];
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
imgElement.onload = resolve
|
imgElement.onload = resolve;
|
||||||
})
|
});
|
||||||
// 将图片转化为张量
|
// 将图片转化为张量
|
||||||
const imgTensor = tf.browser.fromPixels(imgElement)
|
const imgTensor = tf.browser.fromPixels(imgElement);
|
||||||
|
|
||||||
// 使用神经网络模型进行推理,获取名为"conv_preds"的卷积层激活值
|
// 使用神经网络模型进行推理,获取名为"conv_preds"的卷积层激活值
|
||||||
// let activation = net.infer(imgTensor, "conv_preds");
|
// let activation = net.infer(imgTensor, "conv_preds");
|
||||||
@@ -107,13 +114,13 @@ async function train() {
|
|||||||
.toFloat()
|
.toFloat()
|
||||||
.div(tf.scalar(127.5))
|
.div(tf.scalar(127.5))
|
||||||
.sub(tf.scalar(1))
|
.sub(tf.scalar(1))
|
||||||
.expandDims(0)
|
.expandDims(0);
|
||||||
|
|
||||||
const features = featureExtractor.predict(preprocessedImg)
|
const features = featureExtractor.predict(preprocessedImg);
|
||||||
|
|
||||||
// 将特征输入你的模型
|
// 将特征输入你的模型
|
||||||
// const predictions = net.predict(features);
|
// const predictions = net.predict(features);
|
||||||
let activation = features
|
let activation = features;
|
||||||
// if (activation.shape.length === 3) {
|
// if (activation.shape.length === 3) {
|
||||||
// activation = activation.reshape([1, 1024]);
|
// activation = activation.reshape([1, 1024]);
|
||||||
// }
|
// }
|
||||||
@@ -123,33 +130,32 @@ async function train() {
|
|||||||
// 为了适配后续分类层或特征可视化的输入要求
|
// 为了适配后续分类层或特征可视化的输入要求
|
||||||
|
|
||||||
// 转换为one-hot编码
|
// 转换为one-hot编码
|
||||||
const y = tf.oneHot(tf.tensor1d([classId]).toInt(), NUM_CLASSES)
|
const y = tf.oneHot(tf.tensor1d([classId]).toInt(), NUM_CLASSES);
|
||||||
// 初始化xs和ys
|
// 初始化xs和ys
|
||||||
if (xs == null) {
|
if (xs == null) {
|
||||||
xs = activation.clone()
|
xs = activation.clone();
|
||||||
ys = y.clone()
|
ys = y.clone();
|
||||||
}
|
} else {
|
||||||
else {
|
const oldXs = xs;
|
||||||
const oldXs = xs
|
xs = oldXs.concat(activation, 0);
|
||||||
xs = oldXs.concat(activation, 0)
|
oldXs.dispose();
|
||||||
oldXs.dispose()
|
|
||||||
|
|
||||||
const oldYs = ys
|
const oldYs = ys;
|
||||||
ys = oldYs.concat(y, 0)
|
ys = oldYs.concat(y, 0);
|
||||||
oldYs.dispose()
|
oldYs.dispose();
|
||||||
}
|
}
|
||||||
y.dispose()
|
y.dispose();
|
||||||
imgTensor.dispose()
|
imgTensor.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 训练过程可视化相关
|
// 训练过程可视化相关
|
||||||
lossValues = []
|
lossValues = [];
|
||||||
const metrics = ['loss', 'acc', 'val_loss', 'val_acc', 'accuracy', 'val_accuracy']
|
const metrics = ["loss", "acc", "val_loss", "val_acc", "accuracy", "val_accuracy"];
|
||||||
const container = document.getElementById('vis-left-panel') || {
|
const container = document.getElementById("vis-left-panel") || {
|
||||||
name: '训练过程',
|
name: "训练过程",
|
||||||
tab: '训练',
|
tab: "训练",
|
||||||
}
|
};
|
||||||
// 训练模型
|
// 训练模型
|
||||||
await model.fit(xs, ys, {
|
await model.fit(xs, ys, {
|
||||||
epochs: 20,
|
epochs: 20,
|
||||||
@@ -157,209 +163,220 @@ async function train() {
|
|||||||
shuffle: true,
|
shuffle: true,
|
||||||
validationSplit: 0.2,
|
validationSplit: 0.2,
|
||||||
callbacks: tfvis.show.fitCallbacks(container, metrics, {
|
callbacks: tfvis.show.fitCallbacks(container, metrics, {
|
||||||
callbacks: ['onEpochEnd'],
|
callbacks: ["onEpochEnd"],
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
console.log('训练完成')
|
console.log("训练完成");
|
||||||
// 与显示进度条相关
|
// 与显示进度条相关
|
||||||
classList.value = picList.value
|
classList.value = picList.value
|
||||||
.filter(item => item.disabled !== true)
|
.filter((item) => item.disabled !== true)
|
||||||
.map((item, idx) => ({
|
.map((item, idx) => ({
|
||||||
name: item.title,
|
name: item.title,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
}))
|
}));
|
||||||
console.log(classList.value)
|
console.log(classList.value);
|
||||||
states.value.isTraining = 2
|
states.value.isTraining = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
// 没训练完成跳过
|
// 没训练完成跳过
|
||||||
if (states.value.isTraining !== 2)
|
if (states.value.isTraining !== 2) return;
|
||||||
return
|
|
||||||
// 输入是“上传图片”时跳过
|
// 输入是“上传图片”时跳过
|
||||||
if (uploadedImg.value !== '')
|
if (uploadedImg.value !== "") return;
|
||||||
return
|
|
||||||
// 通知摄像头拍摄照片
|
// 通知摄像头拍摄照片
|
||||||
emit('shot')
|
emit("shot");
|
||||||
// 加载拍摄的照片
|
// 加载拍摄的照片
|
||||||
const img = shotList.value[shotList.value.length - 1]
|
const img = shotList.value[shotList.value.length - 1];
|
||||||
if (!img || img === 'data:,') {
|
if (!img || img === "data:,") {
|
||||||
ElMessage.error('未获取到有效样本')
|
ElMessage.error("未获取到有效样本");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const imgElement = new Image()
|
const imgElement = new Image();
|
||||||
imgElement.src = img
|
imgElement.src = img;
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
imgElement.onload = resolve
|
imgElement.onload = resolve;
|
||||||
})
|
});
|
||||||
// 将图片转换为张量
|
// 将图片转换为张量
|
||||||
const imgTensor = tf.browser.fromPixels(imgElement)
|
const imgTensor = tf.browser.fromPixels(imgElement);
|
||||||
// let activation = net.infer(imgTensor, "conv_preds");
|
// let activation = net.infer(imgTensor, "conv_preds");
|
||||||
let resized = tf.image.resizeBilinear(imgTensor, [224, 224])
|
let resized = tf.image.resizeBilinear(imgTensor, [224, 224]);
|
||||||
let batched = resized.expandDims(0)
|
let batched = resized.expandDims(0);
|
||||||
let normalized = batched.div(255)
|
let normalized = batched.div(255);
|
||||||
// let activation = net.predict(imgTensor);
|
// let activation = net.predict(imgTensor);
|
||||||
let activation = featureExtractor.predict(normalized)
|
let activation = featureExtractor.predict(normalized);
|
||||||
const pred = model.predict(activation)
|
const pred = model.predict(activation);
|
||||||
const predArr = await pred.data()
|
const predArr = await pred.data();
|
||||||
// console.log(predArr)
|
// console.log(predArr)
|
||||||
classList.value = [
|
classList.value = [
|
||||||
...classList.value.map((item, idx) => ({
|
...classList.value.map((item, idx) => ({
|
||||||
...item,
|
...item,
|
||||||
progress: Number((predArr[idx] * 100).toFixed(2)),
|
progress: Number((predArr[idx] * 100).toFixed(2)),
|
||||||
})),
|
})),
|
||||||
]
|
];
|
||||||
// console.log(classList.value)
|
// console.log(classList.value)
|
||||||
imgTensor.dispose()
|
imgTensor.dispose();
|
||||||
activation.dispose()
|
activation.dispose();
|
||||||
pred.dispose()
|
pred.dispose();
|
||||||
}, 200)
|
}, 200);
|
||||||
|
|
||||||
const showVisPanel = ref(false)
|
const showVisPanel = ref(false);
|
||||||
const uploadedImg = ref('')
|
const uploadedImg = ref("");
|
||||||
const uploadedResult = ref('')
|
const uploadedResult = ref("");
|
||||||
const panelTop = ref('20%')
|
const panelTop = ref("20%");
|
||||||
const panelRight = ref('20%')
|
const panelRight = ref("20%");
|
||||||
|
|
||||||
async function exportModel() {
|
async function exportModel() {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
ElMessage.error('模型尚未训练完成')
|
ElMessage.error("模型尚未训练完成");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// 导出模型到本地文件系统
|
// 导出模型到本地文件系统
|
||||||
await model.save(`downloads://${modelName.value == '' ? 'my-model' : modelName.value}`)
|
await model.save(
|
||||||
ElMessage.success('模型导出成功')
|
`downloads://${modelName.value == "" ? "my-model" : modelName.value}`
|
||||||
}
|
);
|
||||||
catch (error) {
|
ElMessage.success("模型导出成功");
|
||||||
ElMessage.error(`模型导出失败: ${error.message}`)
|
} catch (error) {
|
||||||
|
ElMessage.error(`模型导出失败: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleUpload(file) {
|
async function handleUpload(file) {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader();
|
||||||
reader.onload = async (e) => {
|
reader.onload = async (e) => {
|
||||||
uploadedImg.value = e.target.result
|
uploadedImg.value = e.target.result;
|
||||||
if (!featureExtractor || !model) {
|
if (!featureExtractor || !model) {
|
||||||
ElMessage.error('请先完成模型训练')
|
ElMessage.error("请先完成模型训练");
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
const imgElement = new window.Image()
|
const imgElement = new window.Image();
|
||||||
imgElement.src = uploadedImg.value
|
imgElement.src = uploadedImg.value;
|
||||||
await new Promise(resolve => (imgElement.onload = resolve))
|
await new Promise((resolve) => (imgElement.onload = resolve));
|
||||||
const imgTensor = tf.browser.fromPixels(imgElement)
|
const imgTensor = tf.browser.fromPixels(imgElement);
|
||||||
// let activation = net.infer(imgTensor, "conv_preds");
|
// let activation = net.infer(imgTensor, "conv_preds");
|
||||||
let resized = tf.image.resizeBilinear(imgTensor, [224, 224])
|
let resized = tf.image.resizeBilinear(imgTensor, [224, 224]);
|
||||||
let batched = resized.expandDims(0)
|
let batched = resized.expandDims(0);
|
||||||
let normalized = batched.div(255)
|
let normalized = batched.div(255);
|
||||||
// let activation = net.predict(imgTensor);
|
// let activation = net.predict(imgTensor);
|
||||||
let activation = featureExtractor.predict(normalized)
|
let activation = featureExtractor.predict(normalized);
|
||||||
const pred = model.predict(activation)
|
const pred = model.predict(activation);
|
||||||
const predArr = await pred.data()
|
const predArr = await pred.data();
|
||||||
classList.value = [
|
classList.value = [
|
||||||
...classList.value.map((item, idx) => ({
|
...classList.value.map((item, idx) => ({
|
||||||
...item,
|
...item,
|
||||||
progress: Number((predArr[idx] * 100).toFixed(2)),
|
progress: Number((predArr[idx] * 100).toFixed(2)),
|
||||||
})),
|
})),
|
||||||
]
|
];
|
||||||
const maxIdx = predArr.indexOf(Math.max(...predArr))
|
const maxIdx = predArr.indexOf(Math.max(...predArr));
|
||||||
uploadedResult.value = classList.value[maxIdx]?.name || '未知'
|
uploadedResult.value = classList.value[maxIdx]?.name || "未知";
|
||||||
imgTensor.dispose()
|
imgTensor.dispose();
|
||||||
activation.dispose()
|
activation.dispose();
|
||||||
pred.dispose()
|
pred.dispose();
|
||||||
}
|
};
|
||||||
reader.readAsDataURL(file)
|
reader.readAsDataURL(file);
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchToUpload() {
|
function switchToUpload() {
|
||||||
uploadedImg.value = ''
|
uploadedImg.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
let startX = 0
|
let startX = 0;
|
||||||
let startY = 0
|
let startY = 0;
|
||||||
let startTop = 0
|
let startTop = 0;
|
||||||
let startRight = 0
|
let startRight = 0;
|
||||||
|
|
||||||
function onDragStart(e) {
|
function onDragStart(e) {
|
||||||
if (e.button !== 0)
|
if (e.button !== 0) return;
|
||||||
return
|
startX = e.clientX;
|
||||||
startX = e.clientX
|
startY = e.clientY;
|
||||||
startY = e.clientY
|
const topVal = document.getElementById("vis-left-panel-wrapper").style.top;
|
||||||
const topVal = document.getElementById('vis-left-panel-wrapper').style.top
|
const rightVal = document.getElementById("vis-left-panel-wrapper").style.right;
|
||||||
const rightVal = document.getElementById('vis-left-panel-wrapper').style.right
|
startTop = topVal.endsWith("%")
|
||||||
startTop = topVal.endsWith('%')
|
|
||||||
? (window.innerHeight * Number.parseFloat(topVal)) / 100
|
? (window.innerHeight * Number.parseFloat(topVal)) / 100
|
||||||
: Number.parseFloat(topVal)
|
: Number.parseFloat(topVal);
|
||||||
startRight = rightVal.endsWith('%')
|
startRight = rightVal.endsWith("%")
|
||||||
? (window.innerWidth * Number.parseFloat(rightVal)) / 100
|
? (window.innerWidth * Number.parseFloat(rightVal)) / 100
|
||||||
: Number.parseFloat(rightVal)
|
: Number.parseFloat(rightVal);
|
||||||
|
|
||||||
document.addEventListener('mousemove', onDragging)
|
document.addEventListener("mousemove", onDragging);
|
||||||
document.addEventListener('mouseup', onDragEnd)
|
document.addEventListener("mouseup", onDragEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDragging(e) {
|
function onDragging(e) {
|
||||||
const deltaX = e.clientX - startX
|
const deltaX = e.clientX - startX;
|
||||||
const deltaY = e.clientY - startY
|
const deltaY = e.clientY - startY;
|
||||||
let newTop = startTop + deltaY
|
let newTop = startTop + deltaY;
|
||||||
let newRight = startRight - deltaX
|
let newRight = startRight - deltaX;
|
||||||
newTop = Math.max(0, Math.min(window.innerHeight - 100, newTop))
|
newTop = Math.max(0, Math.min(window.innerHeight - 100, newTop));
|
||||||
newRight = Math.max(0, Math.min(window.innerWidth - 200, newRight))
|
newRight = Math.max(0, Math.min(window.innerWidth - 200, newRight));
|
||||||
panelTop.value = `${newTop}px`
|
panelTop.value = `${newTop}px`;
|
||||||
panelRight.value = `${newRight}px`
|
panelRight.value = `${newRight}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDragEnd() {
|
function onDragEnd() {
|
||||||
document.removeEventListener('mousemove', onDragging)
|
document.removeEventListener("mousemove", onDragging);
|
||||||
document.removeEventListener('mouseup', onDragEnd)
|
document.removeEventListener("mouseup", onDragEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ train })
|
defineExpose({ train });
|
||||||
|
|
||||||
const modelName = ref('')
|
const modelName = ref("");
|
||||||
async function saveModel() {
|
async function saveModel() {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
ElMessage.error('模型尚未训练完成')
|
ElMessage.error("模型尚未训练完成");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// 导出模型到本地文件系统
|
// 导出模型到本地文件系统
|
||||||
await model.save(`indexeddb://${modelName.value == '' ? 'my-model' : modelName.value}`)
|
await model.save(
|
||||||
ElMessage.success('模型保存成功')
|
`indexeddb://${modelName.value == "" ? "my-model" : modelName.value}`
|
||||||
}
|
);
|
||||||
catch (error) {
|
ElMessage.success("模型保存成功");
|
||||||
ElMessage.error(`模型保存失败: ${error.message}`)
|
} catch (error) {
|
||||||
|
ElMessage.error(`模型保存失败: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-show="showVisPanel" id="vis-left-panel-wrapper" class="vis-left-panel-wrapper"
|
<div
|
||||||
:style="`right: ${panelRight}; top: ${panelTop};`">
|
v-show="showVisPanel"
|
||||||
|
id="vis-left-panel-wrapper"
|
||||||
|
class="vis-left-panel-wrapper"
|
||||||
|
:style="`right: ${panelRight}; top: ${panelTop};`"
|
||||||
|
>
|
||||||
<div class="vis-left-panel-inner-wrapper">
|
<div class="vis-left-panel-inner-wrapper">
|
||||||
<div class="vis-left-panel-title" style="" @mousedown="onDragStart">
|
<div class="vis-left-panel-title" style="" @mousedown="onDragStart">
|
||||||
<span> 训练过程可视化 </span>
|
<span> 训练过程可视化 </span>
|
||||||
<ElButton size="small" plain @click="showVisPanel = false">
|
<ElButton size="small" plain @click="showVisPanel = false"> 隐藏 </ElButton>
|
||||||
隐藏
|
|
||||||
</ElButton>
|
|
||||||
</div>
|
|
||||||
<div id="vis-left-panel" class="vis-left-panel">
|
|
||||||
训练准备中……
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id="vis-left-panel" class="vis-left-panel">训练准备中……</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ElCard v-if="states.isTraining === 2" class="model-area">
|
<ElCard v-if="states.isTraining === 2" class="model-area">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
模型
|
模型
|
||||||
<ElButton v-if="!showVisPanel" size="small" style="margin-left: 10px" type="primary" plain
|
<ElButton
|
||||||
@click="showVisPanel = true">
|
v-if="!showVisPanel"
|
||||||
|
size="small"
|
||||||
|
style="margin-left: 10px"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
@click="showVisPanel = true"
|
||||||
|
>
|
||||||
显示训练过程
|
显示训练过程
|
||||||
</ElButton>
|
</ElButton>
|
||||||
<ElButton v-if="states.isTraining === 2" size="small" style="margin-left: 10px" type="success"
|
<ElButton
|
||||||
plain @click="exportModel">
|
v-if="states.isTraining === 2"
|
||||||
|
size="small"
|
||||||
|
style="margin-left: 10px"
|
||||||
|
type="success"
|
||||||
|
plain
|
||||||
|
@click="exportModel"
|
||||||
|
>
|
||||||
模型导出至本地
|
模型导出至本地
|
||||||
</ElButton>
|
</ElButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -367,53 +384,79 @@ async function saveModel() {
|
|||||||
|
|
||||||
<ElRow class="model-item" style="flex-direction: column; align-items: flex-center">
|
<ElRow class="model-item" style="flex-direction: column; align-items: flex-center">
|
||||||
<ElRow>
|
<ElRow>
|
||||||
<ElCol :span="6" style="display: flex; align-items: center; text-align: right;">
|
<ElCol :span="6" style="display: flex; align-items: center; text-align: right">
|
||||||
名称:
|
名称:
|
||||||
</ElCol>
|
</ElCol>
|
||||||
<ElCol :span="12">
|
<ElCol :span="12">
|
||||||
<ElInput v-model="modelName" placeholder="请输入模型名称" />
|
<ElInput v-model="modelName" placeholder="请输入模型名称" />
|
||||||
</ElCol>
|
</ElCol>
|
||||||
<ElCol :span="4" style="display: flex; align-items: center;">
|
<ElCol :span="4" style="display: flex; align-items: center">
|
||||||
<ElButton style="margin: auto 5px" type="primary" plain size="small" @click="saveModel">
|
<ElButton
|
||||||
|
style="margin: auto 5px"
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
size="small"
|
||||||
|
@click="saveModel"
|
||||||
|
>
|
||||||
保存
|
保存
|
||||||
</ElButton>
|
</ElButton>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
</ElRow>
|
</ElRow>
|
||||||
|
</ElRow>
|
||||||
<ElRow class="model-item">
|
<ElRow class="model-item">
|
||||||
<b>输入</b>
|
<b>输入</b>
|
||||||
</ElRow>
|
</ElRow>
|
||||||
|
<ElRow class="model-item">
|
||||||
<div v-if="!uploadedImg" style="margin: auto">
|
<div v-if="!uploadedImg" style="margin: auto">
|
||||||
上方拍摄内容
|
上方拍摄内容
|
||||||
<ElUpload :show-file-list="false" accept="image/*" :before-upload="handleUpload">
|
<ElUpload
|
||||||
<ElButton size="small" type="success">
|
:show-file-list="false"
|
||||||
切换为上传图片
|
accept="image/*"
|
||||||
</ElButton>
|
:before-upload="handleUpload"
|
||||||
|
>
|
||||||
|
<ElButton size="small" type="success"> 切换为上传图片 </ElButton>
|
||||||
</ElUpload>
|
</ElUpload>
|
||||||
</div>
|
</div>
|
||||||
<div v-else style="margin: auto">
|
<div v-else style="margin: auto">
|
||||||
下方上传图片 <br>
|
下方上传图片 <br />
|
||||||
<ElButton size="small" type="success" plain @click="switchToUpload">
|
<ElButton size="small" type="success" plain @click="switchToUpload">
|
||||||
切换为上方拍摄内容
|
切换为上方拍摄内容
|
||||||
</ElButton>
|
</ElButton>
|
||||||
<ElUpload :show-file-list="false" accept="image/*" :before-upload="handleUpload">
|
<ElUpload
|
||||||
<ElButton size="small" type="success">
|
:show-file-list="false"
|
||||||
重新上传一张
|
accept="image/*"
|
||||||
</ElButton>
|
:before-upload="handleUpload"
|
||||||
|
>
|
||||||
|
<ElButton size="small" type="success"> 重新上传一张 </ElButton>
|
||||||
</ElUpload>
|
</ElUpload>
|
||||||
<img :src="uploadedImg" alt="用户上传图片"
|
<img
|
||||||
style="max-width: 100%; max-height: 150px; border-radius: 10px">
|
:src="uploadedImg"
|
||||||
|
alt="用户上传图片"
|
||||||
|
style="max-width: 100%; max-height: 150px; border-radius: 10px"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ElRow>
|
</ElRow>
|
||||||
<ElRow class="model-item">
|
<ElRow class="model-item">
|
||||||
<b>输出</b>
|
<b>输出</b>
|
||||||
</ElRow>
|
</ElRow>
|
||||||
<ElRow v-for="(item, idx) in classList" :key="`${item.name}-${idx}`" class="model-item">
|
<ElRow
|
||||||
|
v-for="(item, idx) in classList"
|
||||||
|
:key="`${item.name}-${idx}`"
|
||||||
|
class="model-item"
|
||||||
|
>
|
||||||
<ElCol :span="6">
|
<ElCol :span="6">
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</ElCol>
|
</ElCol>
|
||||||
<ElCol :span="18">
|
<ElCol :span="18">
|
||||||
<ElProgress class="progress" :text-inside="true" :stroke-width="20" :percentage="item.progress"
|
<ElProgress
|
||||||
:color="progressColors[idx % progressColors.length]" striped :format="(p) => `${p}%`" />
|
class="progress"
|
||||||
|
:text-inside="true"
|
||||||
|
:stroke-width="20"
|
||||||
|
:percentage="item.progress"
|
||||||
|
:color="progressColors[idx % progressColors.length]"
|
||||||
|
striped
|
||||||
|
:format="(p) => `${p}%`"
|
||||||
|
/>
|
||||||
</ElCol>
|
</ElCol>
|
||||||
</ElRow>
|
</ElRow>
|
||||||
</ElCard>
|
</ElCard>
|
||||||
|
|||||||
@@ -3724,6 +3724,128 @@
|
|||||||
</value>
|
</value>
|
||||||
</block>
|
</block>
|
||||||
</category>
|
</category>
|
||||||
|
<category id="catTensorflow" name="Tensorflow" colour="#1216ab">
|
||||||
|
<button text="导入模型" callbackKey="handleModels"></button>
|
||||||
|
<block type="tensorflow_init_tensor">
|
||||||
|
<value name="VAR">
|
||||||
|
<shadow type="list_many_input">
|
||||||
|
<field name="CONTENT">1,2,3,4,5</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_sequential">
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_layers_dense">
|
||||||
|
<value name="VAR1">
|
||||||
|
<shadow type="math_number">
|
||||||
|
<field name="NUM">1</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="VAR2">
|
||||||
|
<shadow type="list_many_input">
|
||||||
|
<field name="CONTENT">1</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_add">
|
||||||
|
<value name="VAR1">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">model</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="VAR2">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">layer</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_compile">
|
||||||
|
<value name="VAR1">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">model</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_fit">
|
||||||
|
<value name="VAR1">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">model</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="VAR2">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">xs</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="VAR3">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">ys</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="VAR4">
|
||||||
|
<shadow type="math_number">
|
||||||
|
<field name="NUM">1</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="VAR5">
|
||||||
|
<shadow type="math_number">
|
||||||
|
<field name="NUM">0</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_get_loss">
|
||||||
|
<value name="VAR">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">history</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_predict">
|
||||||
|
<value name="VAR1">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">model</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="VAR2">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">inputTensor</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_get_tensor_data">
|
||||||
|
<value name="VAR">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">outputTensor</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_save_or_export_model">
|
||||||
|
<value name="NAME1">
|
||||||
|
<shadow type="variables_get">
|
||||||
|
<field name="VAR">model</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
<value name="NAME2">
|
||||||
|
<shadow type="text">
|
||||||
|
<field name="TEXT">my-model</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_use_load_model">
|
||||||
|
<value name="NAME">
|
||||||
|
<shadow type="text">
|
||||||
|
<field name="TEXT">my-model</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
<block type="tensorflow_prepare_picture">
|
||||||
|
<value name="NAME">
|
||||||
|
<shadow type="text">
|
||||||
|
<field name="TEXT">1.jpg</field>
|
||||||
|
</shadow>
|
||||||
|
</value>
|
||||||
|
</block>
|
||||||
|
</category>
|
||||||
<category id="catFactory" name="Factory" colour="#777777">
|
<category id="catFactory" name="Factory" colour="#777777">
|
||||||
<block type="factory_import"></block>
|
<block type="factory_import"></block>
|
||||||
<block type="factory_from_import"></block>
|
<block type="factory_from_import"></block>
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
from pyodide.ffi import to_js, create_proxy
|
||||||
|
import js
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from . import layers
|
||||||
|
|
||||||
|
|
||||||
|
def __cache_model(file_path):
|
||||||
|
data = json.load(open(file_path, 'r'))
|
||||||
|
f = open(file_path, 'rb')
|
||||||
|
js.tensorflow.setModelsValue(file_path, to_js(f.read()))
|
||||||
|
f.close()
|
||||||
|
folder_path = os.path.dirname(file_path)
|
||||||
|
for item in data['weightsManifest']:
|
||||||
|
for current_path in item['paths']:
|
||||||
|
bin_file_path = '{}/{}'.format(folder_path, current_path)
|
||||||
|
f = open(bin_file_path, 'rb')
|
||||||
|
js.tensorflow.setModelsValue(bin_file_path, to_js(f.read()))
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def load_graph_model(file_path):
|
||||||
|
__cache_model(file_path)
|
||||||
|
model = await js.tensorflow.loadGraphModel(file_path)
|
||||||
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
async def load_layers_model(file_path):
|
||||||
|
__cache_model(file_path)
|
||||||
|
model = await js.tensorflow.loadLayersModel(file_path)
|
||||||
|
return model
|
||||||
|
|
||||||
|
def tensor(data):
|
||||||
|
return js.tf.tensor(to_js(data))
|
||||||
|
|
||||||
|
def sequential():
|
||||||
|
return js.tf.sequential()
|
||||||
|
|
||||||
|
async def load_model(name):
|
||||||
|
model = await js.tf.loadLayersModel(f"indexeddb://{name}")
|
||||||
|
return model
|
||||||
|
|
||||||
|
async def prepare_qmyixtxi(imgTensor):
|
||||||
|
return await js.prepare_qmyixtxi(imgTensor)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from .activation import *
|
||||||
|
from .core import *
|
||||||
|
|
||||||
|
from pyodide.ffi import to_js, create_proxy
|
||||||
|
import js
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import js
|
||||||
|
|
||||||
|
|
||||||
|
def elu(*args, **kwargs):
|
||||||
|
'''
|
||||||
|
f(x) = alpha * (exp(x) - 1.) for x < 0, f(x) = x for x >= 0.
|
||||||
|
'''
|
||||||
|
js.tensorflow.layers.elu(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def leaky_relu(*args, **kwargs):
|
||||||
|
'''
|
||||||
|
f(x) = alpha * x for x < 0. f(x) = x for x >= 0.
|
||||||
|
'''
|
||||||
|
js.tensorflow.layers.leakyReLU(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def prelu(*args, **kwargs):
|
||||||
|
'''
|
||||||
|
f(x) = alpha * x for x < 0. f(x) = x for x >= 0.
|
||||||
|
'''
|
||||||
|
js.tensorflow.layers.prelu(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def relu(*args, **kwargs):
|
||||||
|
js.tensorflow.layers.relu(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def softmax(*args, **kwargs):
|
||||||
|
js.tensorflow.layers.softmax(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def thresholded_relu(*args, **kwargs):
|
||||||
|
'''
|
||||||
|
f(x) = x for x > theta, f(x) = 0 otherwise.
|
||||||
|
'''
|
||||||
|
js.tensorflow.layers.thresholdedReLU(*args, **kwargs)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import js
|
||||||
|
from pyodide.ffi import to_js
|
||||||
|
|
||||||
|
def dense(units, input_shape=None):
|
||||||
|
return js.tf.layers.dense(units=units, inputShape=to_js(input_shape))
|
||||||
BIN
boards/default_src/python_pyodide/whl/tensorflow-project/dist/tensorflow-0.0.1-py3-none-any.whl
vendored
Normal file
BIN
boards/default_src/python_pyodide/whl/tensorflow-project/dist/tensorflow-0.0.1-py3-none-any.whl
vendored
Normal file
Binary file not shown.
@@ -0,0 +1,10 @@
|
|||||||
|
Metadata-Version: 2.4
|
||||||
|
Name: tensorflow
|
||||||
|
Version: 0.0.1
|
||||||
|
Summary: 适用于pyodide的tensorflowjs包
|
||||||
|
Author: Mixly Team
|
||||||
|
Author-email:
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Dynamic: author
|
||||||
|
Dynamic: classifier
|
||||||
|
Dynamic: summary
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
setup.py
|
||||||
|
tensorflow/__init__.py
|
||||||
|
tensorflow.egg-info/PKG-INFO
|
||||||
|
tensorflow.egg-info/SOURCES.txt
|
||||||
|
tensorflow.egg-info/dependency_links.txt
|
||||||
|
tensorflow.egg-info/top_level.txt
|
||||||
|
tensorflow/layers/__init__.py
|
||||||
|
tensorflow/layers/activation.py
|
||||||
|
tensorflow/layers/base.py
|
||||||
|
tensorflow/layers/core.py
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
tensorflow
|
||||||
@@ -2,6 +2,7 @@ from pyodide.ffi import to_js, create_proxy
|
|||||||
import js
|
import js
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
from . import layers
|
||||||
|
|
||||||
|
|
||||||
def __cache_model(file_path):
|
def __cache_model(file_path):
|
||||||
@@ -28,3 +29,16 @@ async def load_layers_model(file_path):
|
|||||||
__cache_model(file_path)
|
__cache_model(file_path)
|
||||||
model = await js.tensorflow.loadLayersModel(file_path)
|
model = await js.tensorflow.loadLayersModel(file_path)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
def tensor(data):
|
||||||
|
return js.tf.tensor(to_js(data))
|
||||||
|
|
||||||
|
def sequential():
|
||||||
|
return js.tf.sequential()
|
||||||
|
|
||||||
|
async def load_model(name):
|
||||||
|
model = await js.tf.loadLayersModel(f"indexeddb://{name}")
|
||||||
|
return model
|
||||||
|
|
||||||
|
async def prepare_qmyixtxi(imgTensor):
|
||||||
|
return await js.prepare_qmyixtxi(imgTensor)
|
||||||
@@ -1 +1,5 @@
|
|||||||
from activation import *
|
from .activation import *
|
||||||
|
from .core import *
|
||||||
|
|
||||||
|
from pyodide.ffi import to_js, create_proxy
|
||||||
|
import js
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import js
|
||||||
|
from pyodide.ffi import to_js
|
||||||
|
|
||||||
|
def dense(units, input_shape=None):
|
||||||
|
return js.tf.layers.dense(units=units, inputShape=to_js(input_shape))
|
||||||
BIN
common/media/tfmodel/group1-shard1of3.bin
Normal file
BIN
common/media/tfmodel/group1-shard1of3.bin
Normal file
Binary file not shown.
BIN
common/media/tfmodel/group1-shard2of3.bin
Normal file
BIN
common/media/tfmodel/group1-shard2of3.bin
Normal file
Binary file not shown.
BIN
common/media/tfmodel/group1-shard3of3.bin
Normal file
BIN
common/media/tfmodel/group1-shard3of3.bin
Normal file
Binary file not shown.
1
common/media/tfmodel/model.json
Normal file
1
common/media/tfmodel/model.json
Normal file
File diff suppressed because one or more lines are too long
@@ -4009,4 +4009,36 @@ En.MIXLY_TINY_WEB_DB_START_NUMBER = 'Start number';
|
|||||||
En.MIXLY_TINY_WEB_DB_VARIABLE_NUMBER = 'Number of variables';
|
En.MIXLY_TINY_WEB_DB_VARIABLE_NUMBER = 'Number of variables';
|
||||||
En.MIXLY_TINY_WEB_DB_SEARCH_VARS = 'Characters in variable names';
|
En.MIXLY_TINY_WEB_DB_SEARCH_VARS = 'Characters in variable names';
|
||||||
|
|
||||||
|
|
||||||
|
En.MIXLY_TENSORFLOW_INIT_TENSOR = 'Initialize tensor as';
|
||||||
|
En.MIXLY_TENSORFLOW_SEQUENTIAL = 'Initialize sequential model';
|
||||||
|
En.MIXLY_TENSORFLOW_INIT_LAYERS_DENSE_LAYER = 'Build dense layer';
|
||||||
|
En.MIXLY_TENSORFLOW_OUTPUT_DIMENSION = 'Output dimension';
|
||||||
|
En.MIXLY_TENSORFLOW_INPUT_SHAPE = 'Input shape';
|
||||||
|
En.MIXLY_TENSORFLOW_MODEL = 'Model';
|
||||||
|
En.MIXLY_TENSORFLOW_ADD_LAYER = 'Add layer';
|
||||||
|
En.MIXLY_TENSORFLOW_COMPILE_MODEL = 'Compile model';
|
||||||
|
En.MIXLY_TENSORFLOW_LOSS_FUNCTION_TYPE = 'Loss function type';
|
||||||
|
En.MIXLY_TENSORFLOW_MEAN_SQUARED_ERROR = 'Mean squared error';
|
||||||
|
En.MIXLY_TENSORFLOW_OPTIMIZER = 'Optimizer';
|
||||||
|
En.MIXLY_TENSORFLOW_SGD = 'Stochastic gradient descent';
|
||||||
|
En.MIXLY_TENSORFLOW_FIT_MODEL = 'Train model';
|
||||||
|
En.MIXLY_TENSORFLOW_FIT_INPUT_DATA = 'Input data';
|
||||||
|
En.MIXLY_TENSORFLOW_FIT_TARGET_DATA = 'Target data';
|
||||||
|
En.MIXLY_TENSORFLOW_FIT_EPOCHS = 'Training epochs';
|
||||||
|
En.MIXLY_TENSORFLOW_FIT_VERBOSE = 'Verbose level';
|
||||||
|
En.MIXLY_TENSORFLOW_FIT_RETURN_HISTORY = 'Return training history object';
|
||||||
|
En.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY = 'From training history object';
|
||||||
|
En.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY_2 = 'Get training loss values array';
|
||||||
|
En.MIXLY_TENSORFLOW_PREDICT = 'Use model for prediction';
|
||||||
|
En.MIXLY_TENSORFLOW_PREDICT_INPUT_DATA = 'Input data';
|
||||||
|
En.MIXLY_TENSORFLOW_PREDICT_RETURN_RESULT = 'Return prediction result tensor';
|
||||||
|
En.MIXLY_TENSORFLOW_GET_TENSOR_DATA = 'Get data from tensor';
|
||||||
|
En.MIXLY_TENSORFLOW_SAVE_MODEL = 'Save model';
|
||||||
|
En.MIXLY_TENSORFLOW_EXPORT_MODEL = 'Export model';
|
||||||
|
En.MIXLY_TENSORFLOW_SAVE_MODEL_NAME = 'Name';
|
||||||
|
En.MIXLY_TENSORFLOW_LOAD_MODEL = 'Use imported model';
|
||||||
|
En.MIXLY_TENSORFLOW_MODEL_NAME = 'Model name';
|
||||||
|
En.MIXLY_TENSORFLOW_PREPARE_PICTURE_TO_TENSOR = 'Preprocess image to tensor';
|
||||||
|
En.MIXLY_TENSORFLOW_PREPARE_PICTURE_READ_PICTURE = 'Read image';
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -4168,4 +4168,35 @@ ZhHans.MIXLY_TINY_WEB_DB_START_NUMBER = '起始编号';
|
|||||||
ZhHans.MIXLY_TINY_WEB_DB_VARIABLE_NUMBER = '变量个数';
|
ZhHans.MIXLY_TINY_WEB_DB_VARIABLE_NUMBER = '变量个数';
|
||||||
ZhHans.MIXLY_TINY_WEB_DB_SEARCH_VARS = '变量名包含的字符';
|
ZhHans.MIXLY_TINY_WEB_DB_SEARCH_VARS = '变量名包含的字符';
|
||||||
|
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_INIT_TENSOR = '初始化张量为';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_SEQUENTIAL = '初始化顺序模型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_INIT_LAYERS_DENSE_LAYER = '构建全连接层';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_OUTPUT_DIMENSION = '输出维度';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_INPUT_SHAPE = '输入形状';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_MODEL = '模型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_ADD_LAYER = '添加层';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_COMPILE_MODEL = '编译模型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_LOSS_FUNCTION_TYPE = '损失函数类型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_MEAN_SQUARED_ERROR = '均方误差';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_OPTIMIZER = '优化器';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_SGD = '随机梯度下降法';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_FIT_MODEL = '训练模型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_FIT_INPUT_DATA = '输入数据';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_FIT_TARGET_DATA = '目标数据';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_FIT_EPOCHS = '训练迭代次数';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_FIT_VERBOSE = '日志输出级别';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_FIT_RETURN_HISTORY = '返回训练历史对象';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY = '从训练历史对象';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY_2 = '获取训练损失值数组';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_PREDICT = '使用模型预测';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_PREDICT_INPUT_DATA = '输入数据';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_PREDICT_RETURN_RESULT = '返回预测结果张量';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_GET_TENSOR_DATA = '获取张量中的数据';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_SAVE_MODEL = '保存模型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_EXPORT_MODEL = '导出模型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_SAVE_MODEL_NAME = '名称';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_LOAD_MODEL = '使用导入模型';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_MODEL_NAME = '模型名';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_PREPARE_PICTURE_TO_TENSOR = '预处理图像为张量';
|
||||||
|
ZhHans.MIXLY_TENSORFLOW_PREPARE_PICTURE_READ_PICTURE = '读入图像';
|
||||||
})();
|
})();
|
||||||
@@ -4163,4 +4163,35 @@ ZhHant.MIXLY_TINY_WEB_DB_START_NUMBER = '起始編號';
|
|||||||
ZhHant.MIXLY_TINY_WEB_DB_VARIABLE_NUMBER = '變數個數';
|
ZhHant.MIXLY_TINY_WEB_DB_VARIABLE_NUMBER = '變數個數';
|
||||||
ZhHant.MIXLY_TINY_WEB_DB_SEARCH_VARS = '變數名稱包含的字元';
|
ZhHant.MIXLY_TINY_WEB_DB_SEARCH_VARS = '變數名稱包含的字元';
|
||||||
|
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_INIT_TENSOR = '初始化張量為';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_SEQUENTIAL = '初始化順序模型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_INIT_LAYERS_DENSE_LAYER = '構建全連接層';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_OUTPUT_DIMENSION = '輸出維度';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_INPUT_SHAPE = '輸入形狀';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_MODEL = '模型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_ADD_LAYER = '添加層';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_COMPILE_MODEL = '編譯模型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_LOSS_FUNCTION_TYPE = '損失函數類型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_MEAN_SQUARED_ERROR = '均方誤差';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_OPTIMIZER = '優化器';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_SGD = '隨機梯度下降法';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_FIT_MODEL = '訓練模型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_FIT_INPUT_DATA = '輸入數據';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_FIT_TARGET_DATA = '目標數據';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_FIT_EPOCHS = '訓練迭代次數';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_FIT_VERBOSE = '日誌輸出級別';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_FIT_RETURN_HISTORY = '返回訓練歷史對象';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY = '從訓練歷史對象';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_GET_LOSS_FROM_HISTORY_2 = '獲取訓練損失值數組';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_PREDICT = '使用模型預測';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_PREDICT_INPUT_DATA = '輸入數據';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_PREDICT_RETURN_RESULT = '返回預測結果張量';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_GET_TENSOR_DATA = '獲取張量中的數據';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_SAVE_MODEL = '保存模型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_EXPORT_MODEL = '導出模型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_SAVE_MODEL_NAME = '名稱';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_LOAD_MODEL = '使用導入模型';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_MODEL_NAME = '模型名';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_PREPARE_PICTURE_TO_TENSOR = '預處理圖像為張量';
|
||||||
|
ZhHant.MIXLY_TENSORFLOW_PREPARE_PICTURE_READ_PICTURE = '讀入圖像';
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user