@ai-on-browser/data-analysis-models
Version:
Data analysis model package without any dependencies
83 lines (74 loc) • 1.78 kB
JavaScript
import Tensor from '../../../util/tensor.js'
import Layer from './base.js'
/**
* Variable layer
*/
export default class VariableLayer extends Layer {
/**
* @param {object} config config
* @param {number[] | string} config.size Size of variable
* @param {number} [config.l2_decay] L2 decay
* @param {number} [config.l1_decay] L1 decay
* @param {number[] | number[][] | Tensor} [config.value] Default value
*/
constructor({ size, l2_decay = 0, l1_decay = 0, value = null, ...rest }) {
super(rest)
this._size = size
this._v = null
if (value) {
this._v = Tensor.fromArray(value)
} else if (typeof size !== 'string') {
this._v = Tensor.randn(size)
}
if (this._v && this._v.dimension === 2) {
this._v = this._v.toMatrix()
}
this._l2_decay = l2_decay
this._l1_decay = l1_decay
this._n = 1
}
get dependentLayers() {
const layers = []
if (typeof this._size === 'string') {
layers.push(this._size)
}
return layers
}
bind({ n }) {
this._n = n
}
calc() {
if (!this._v) {
const sizes = this.graph.getNode(this._size).outputValue.value
this._v = Tensor.randn(sizes)
if (this._v.dimension === 2) {
this._v = this._v.toMatrix()
}
}
return this._v
}
grad(bo) {
this._bo = bo
}
update(optimizer) {
const d = this._bo.copy()
d.map(v => v / this._n)
if (this._l2_decay > 0 || this._l1_decay > 0) {
d.map((v, i) => {
const vi = this._v.at(i)
return v + vi * this._l2_decay + Math.sign(vi) * this._l1_decay
})
}
this._v.broadcastOperate(optimizer.delta('v', d), (a, b) => a - b)
}
toObject() {
return {
type: 'variable',
size: this._size,
l2_decay: this._l2_decay,
l1_decay: this._l1_decay,
value: this._v?.toArray(),
}
}
}
VariableLayer.registLayer()