class Diarize::Speaker

Attributes

gender[R]
model[RW]
model_uri[RW]
normalized[W]

Public Class Methods

detection_threshold() click to toggle source
# File lib/diarize/speaker.rb, line 33
def detection_threshold
  @@detection_threshold
end
detection_threshold=(threshold) click to toggle source
# File lib/diarize/speaker.rb, line 29
def detection_threshold=(threshold)
  @@detection_threshold = threshold
end
divergence(speaker1, speaker2) click to toggle source
# File lib/diarize/speaker.rb, line 46
def divergence(speaker1, speaker2)
  # TODO bundle in mean_log_likelihood to weight down unlikely models?
  return unless speaker1.model and speaker2.model
  # MAP Gaussian divergence
  # See "A model space framework for efficient speaker detection", Interspeech'05
  divergence_lium(speaker1, speaker2)
end
divergence_lium(speaker1, speaker2) click to toggle source
# File lib/diarize/speaker.rb, line 54
def divergence_lium(speaker1, speaker2)
  Rjb::import('fr.lium.spkDiarization.libModel.Distance').GDMAP(speaker1.model, speaker2.model)
end
divergence_ruby(speaker1, speaker2) click to toggle source
# File lib/diarize/speaker.rb, line 58
def divergence_ruby(speaker1, speaker2)
  SuperVector.divergence(speaker1.supervector, speaker2.supervector)
end
find_or_create(uri, gender) click to toggle source
# File lib/diarize/speaker.rb, line 41
def find_or_create(uri, gender)
  return @@speakers[uri] if @@speakers[uri]
  @@speakers[uri] = Speaker.new(uri, gender)
end
load_model(filename) click to toggle source
# File lib/diarize/speaker.rb, line 37
def load_model(filename)
  read_gmm(filename)
end
match(speakers) click to toggle source
# File lib/diarize/speaker.rb, line 72
def match(speakers)
  speakers.combination(2).select { |s1, s2| s1.same_speaker_as(s2) }
end
match_sets(speakers1, speakers2) click to toggle source
# File lib/diarize/speaker.rb, line 62
def match_sets(speakers1, speakers2)
  matches = []
  speakers1.each do |s1|
    speakers2.each do |s2|
      matches << [ s1, s2 ] if s1.same_speaker_as(s2)
    end
  end
  matches
end
new(uri = nil, gender = nil, model_file = nil) click to toggle source
# File lib/diarize/speaker.rb, line 13
def initialize(uri = nil, gender = nil, model_file = nil)
  @model      = Speaker.load_model(model_file) if model_file
  @uri        = uri
  @gender     = gender
  @normalized = false
end
ubm() click to toggle source
# File lib/diarize/speaker.rb, line 22
def ubm
  speaker = Speaker.new
  speaker.normalized = true
  speaker.model = Speaker.load_model(File.join(File.expand_path(File.dirname(__FILE__)), 'ubm.gmm'))
  speaker
end

Protected Class Methods

read_gmm(filename) click to toggle source
# File lib/diarize/speaker.rb, line 78
def read_gmm(filename)
  gmmlist = Rjb::JavaObjectWrapper.new("java.util.ArrayList")
  input = Rjb::import('fr.lium.spkDiarization.lib.IOFile').new(filename, 'rb')
  input.open
  Rjb::import('fr.lium.spkDiarization.libModel.ModelIO').readerGMMContainer(input, gmmlist.java_object)
  input.close
  gmmlist.to_a.first.java_object
end

Public Instance Methods

_as_json()
Alias for: as_json
_to_json()
Alias for: to_json
as_json() click to toggle source
# File lib/diarize/speaker.rb, line 166
def as_json
  {
    'gender' => gender,
    'model' => model_uri,
    'mean_log_likelihood' => mean_log_likelihood,
    'supervector_hash' => supervector.hash.to_s
  }
end
Also aliased as: _as_json
mean_log_likelihood() click to toggle source
# File lib/diarize/speaker.rb, line 89
def mean_log_likelihood
  @mean_log_likelihood ? @mean_log_likelihood : model.mean_log_likelihood # Will be NaN if model was loaded from somewhere
end
mean_log_likelihood=(mll) click to toggle source
# File lib/diarize/speaker.rb, line 93
def mean_log_likelihood=(mll)
  @mean_log_likelihood = mll
end
namespaces() click to toggle source
Calls superclass method
# File lib/diarize/speaker.rb, line 145
def namespaces
  super.merge 'ws' => 'http://wsarchive.prototype0.net/ontology/'
end
normalize!() click to toggle source
# File lib/diarize/speaker.rb, line 106
def normalize!
  unless normalized?
    # Applies M-Norm from "D-MAP: a Distance-Normalized MAP Estimation of Speaker Models for Automatic Speaker Verification"
    # to the associated GMM, placing it on a unit hyper-sphere with a UBM centre (model will be at distance one from the UBM
    # according to GDMAP)
    # Using supervectors: vector = (1.0 / distance_to_ubm) * vector + (1.0 - 1.0 / distance_to_ubm) * ubm_vector
    speaker_ubm = Speaker.ubm
    distance_to_ubm = Math.sqrt(Speaker.divergence(self, speaker_ubm))
    model.nb_of_components.times do |k|
      gaussian = model.components.get(k)
      gaussian.dim.times do |i|
        normalized_mean = (1.0 / distance_to_ubm) * gaussian.mean(i) + (1.0 - 1.0 / distance_to_ubm)  * speaker_ubm.model.components.get(k).mean(i)
        gaussian.set_mean(i, normalized_mean)
      end
    end
    @normalized = true
  end
  @normalized
end
normalized?() click to toggle source
# File lib/diarize/speaker.rb, line 102
def normalized?
  !!@normalized
end
rdf_mapping() click to toggle source
# File lib/diarize/speaker.rb, line 157
def rdf_mapping
  {
    'ws:gender' => gender,
    'ws:model' => model_uri,
    'ws:mean_log_likelihood' => mean_log_likelihood,
    'ws:supervector_hash' => supervector.hash.to_s
  }
end
same_speaker_as(other) click to toggle source
# File lib/diarize/speaker.rb, line 126
def same_speaker_as(other)
  # Detection score defined in Ben2005
  return unless [ self.mean_log_likelihood, other.mean_log_likelihood ].min > @@log_likelihood_threshold
  self.normalize!
  other.normalize!
  detection_score = 1.0 - Speaker.divergence(other, self)
  detection_score > @@detection_threshold
end
save_model(filename, force = false) click to toggle source
# File lib/diarize/speaker.rb, line 97
def save_model(filename, force = false)
  raise RuntimeError, "normalized model must be saved with force=true" if !force && normalized?
  write_gmm(filename, @model)
end
supervector() click to toggle source
# File lib/diarize/speaker.rb, line 135
def supervector
  if normalized?
    @supervector ||= begin
      SuperVector.generate_from_model(model)
    end
  else
    SuperVector.generate_from_model(model)
  end
end
to_json() click to toggle source
# File lib/diarize/speaker.rb, line 176
def to_json
  as_json.to_json
end
Also aliased as: _to_json
type_uri() click to toggle source
# File lib/diarize/speaker.rb, line 153
def type_uri
  'ws:Speaker'
end
uri() click to toggle source
# File lib/diarize/speaker.rb, line 149
def uri
  @uri
end

Protected Instance Methods

write_gmm(filename, model) click to toggle source
# File lib/diarize/speaker.rb, line 183
def write_gmm(filename, model)
  gmmlist = Rjb::JavaObjectWrapper.new("java.util.ArrayList")
  gmmlist.java_object.add(model)
  output = Rjb::import('fr.lium.spkDiarization.lib.IOFile').new(filename, 'wb')
  output.open
  Rjb::import('fr.lium.spkDiarization.libModel.ModelIO').writerGMMContainer(output, gmmlist.java_object)
  output.close
end