All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intel.analytics.bigdl.dllib.nn.SoftMarginCriterion.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 The BigDL Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intel.analytics.bigdl.dllib.nn

import com.intel.analytics.bigdl.dllib.nn.abstractnn.TensorCriterion
import com.intel.analytics.bigdl.dllib.tensor._
import com.intel.analytics.bigdl.dllib.tensor.TensorNumericMath.TensorNumeric
import com.intel.analytics.bigdl.dllib.utils.Log4Error

import scala.reflect.ClassTag

/**
 * Creates a criterion that optimizes a two-class classification logistic loss
 * between input x (a Tensor of dimension 1) and output y (which is a tensor
 * containing either 1s or -1s).
 *
 *    loss(x, y) = sum_i (log(1 + exp(-y[i]*x[i]))) / x:nElement()
 *
 * @param sizeAverage The normalization by the number of elements in the input
 *                     can be disabled by setting
 */
@SerialVersionUID(7573077918688542348L)
class SoftMarginCriterion[@specialized(Float, Double) T: ClassTag](var sizeAverage: Boolean = true)
  (implicit ev: TensorNumeric[T])
  extends TensorCriterion[T] {
  def isSizeAverage: Boolean = sizeAverage

  def setSizeAverage(sizeAverage: Boolean): this.type = {
    this.sizeAverage = sizeAverage
    this
  }

  // TODO: replace apply for performance optimization
  override def updateOutput(input: Tensor[T], target: Tensor[T]): T = {
    Log4Error.invalidInputError(input.isSameSizeAs(target),
      "The input should have the same size as target" +
      s"input size ${input.nElement()}, target size ${target.nElement()}")
    var sum = ev.zero
    val func2 = new TensorFunc4[T] {
      override def apply(in: Array[T], index1: Int, tar: Array[T], index2: Int): Unit = {
        val z = ev.log(ev.plus(ev.one, ev.exp(ev.negative(ev.times(in(index1), tar(index2))))))
        sum = ev.plus(sum, z)
      }
    }
    DenseTensorApply.apply2[T](input, target, func2)

    if (sizeAverage) {
      sum = ev.divide(sum, ev.fromType[Int](input.nElement()))
    }

    output = sum
    output
  }

  // TODO: replace apply for performance optimization
  override def updateGradInput(input: Tensor[T], target: Tensor[T]): Tensor[T] = {
    Log4Error.invalidInputError(input.isSameSizeAs(target),
      "The input should have the same size as target" +
      s"input size ${input.nElement()}, target size ${target.nElement()}")
    val norm = if (sizeAverage) {
      ev.divide(ev.one, ev.fromType[Int](input.nElement()))
    } else {
      ev.one
    }

    gradInput.resizeAs(input)
    val func = new TensorFunc6[T] {
      override def apply (gradInput: Array[T], offset1: Int, input: Array[T],
        offset2: Int, target: Array[T], offset3: Int): Unit = {
        val z = ev.exp(ev.negative(ev.times(target(offset1), input(offset2))))
        gradInput(offset1) = ev.divide(
          ev.negative(ev.times(norm, ev.times(target(offset3), z))), ev.plus(ev.one, z))
      }
    }
    DenseTensorApply.apply3[T](gradInput, input, target, func)
    gradInput
  }

  override def canEqual(other: Any): Boolean = other.isInstanceOf[SoftMarginCriterion[T]]

  override def equals(other: Any): Boolean = other match {
    case that: SoftMarginCriterion[T] =>
      (that canEqual this) &&
        gradInput == that.gradInput &&
        sizeAverage == that.sizeAverage
    case _ => false
  }

  override def hashCode(): Int = {
    def getHashcode(state: Any): Int = if (state == null) 0 else state.hashCode()
    val state = Seq(gradInput, sizeAverage)
    state.map(getHashcode).foldLeft(0)((a, b) => 31 * a + b)
  }
}

object SoftMarginCriterion {
  def apply[@specialized(Float, Double) T: ClassTag](sizeAverage: Boolean = true)
      (implicit ev: TensorNumeric[T]): SoftMarginCriterion[T] = {
    new SoftMarginCriterion(sizeAverage)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy