Class: Diarize::Speaker
- Inherits:
-
Object
- Object
- Diarize::Speaker
- Includes:
- ToRdf
- Defined in:
- lib/diarize/speaker.rb
Constant Summary collapse
- @@log_likelihood_threshold =
-33- @@detection_threshold =
0.2
- @@speakers =
{}
Instance Attribute Summary collapse
-
#gender ⇒ Object
readonly
Returns the value of attribute gender.
-
#model ⇒ Object
Returns the value of attribute model.
-
#model_uri ⇒ Object
Returns the value of attribute model_uri.
-
#normalized ⇒ Object
Returns the value of attribute normalized.
Class Method Summary collapse
- .detection_threshold ⇒ Object
- .detection_threshold=(threshold) ⇒ Object
- .divergence(speaker1, speaker2) ⇒ Object
- .divergence_lium(speaker1, speaker2) ⇒ Object
- .divergence_ruby(speaker1, speaker2) ⇒ Object
- .find_or_create(uri, gender) ⇒ Object
- .load_model(filename) ⇒ Object
- .match(speakers) ⇒ Object
- .match_sets(speakers1, speakers2) ⇒ Object
- .read_gmm(filename) ⇒ Object
- .ubm ⇒ Object
Instance Method Summary collapse
-
#initialize(uri = nil, gender = nil, model_file = nil) ⇒ Speaker
constructor
A new instance of Speaker.
- #mean_log_likelihood ⇒ Object
- #mean_log_likelihood=(mll) ⇒ Object
- #namespaces ⇒ Object
- #normalize! ⇒ Object
- #rdf_mapping ⇒ Object
- #same_speaker_as(other) ⇒ Object
- #save_model(filename) ⇒ Object
- #supervector ⇒ Object
- #type_uri ⇒ Object
- #uri ⇒ Object
Constructor Details
#initialize(uri = nil, gender = nil, model_file = nil) ⇒ Speaker
Returns a new instance of Speaker.
11 12 13 14 15 16 |
# File 'lib/diarize/speaker.rb', line 11 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 |
Instance Attribute Details
#gender ⇒ Object (readonly)
Returns the value of attribute gender.
9 10 11 |
# File 'lib/diarize/speaker.rb', line 9 def gender @gender end |
#model ⇒ Object
Returns the value of attribute model.
8 9 10 |
# File 'lib/diarize/speaker.rb', line 8 def model @model end |
#model_uri ⇒ Object
Returns the value of attribute model_uri.
8 9 10 |
# File 'lib/diarize/speaker.rb', line 8 def model_uri @model_uri end |
#normalized ⇒ Object
Returns the value of attribute normalized.
8 9 10 |
# File 'lib/diarize/speaker.rb', line 8 def normalized @normalized end |
Class Method Details
.detection_threshold ⇒ Object
42 43 44 |
# File 'lib/diarize/speaker.rb', line 42 def self.detection_threshold @@detection_threshold end |
.detection_threshold=(threshold) ⇒ Object
38 39 40 |
# File 'lib/diarize/speaker.rb', line 38 def self.detection_threshold=(threshold) @@detection_threshold = threshold end |
.divergence(speaker1, speaker2) ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/diarize/speaker.rb', line 55 def self.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) ⇒ Object
63 64 65 66 |
# File 'lib/diarize/speaker.rb', line 63 def self.divergence_lium(speaker1, speaker2) # fr.lium.spkDiarization.libModel.Distance.GDMAP(speaker1.model, speaker2.model) Rjb::import('fr.lium.spkDiarization.libModel.Distance').GDMAP(speaker1.model, speaker2.model) end |
.divergence_ruby(speaker1, speaker2) ⇒ Object
68 69 70 |
# File 'lib/diarize/speaker.rb', line 68 def self.divergence_ruby(speaker1, speaker2) SuperVector.divergence(speaker1.supervector, speaker2.supervector) end |
.find_or_create(uri, gender) ⇒ Object
50 51 52 53 |
# File 'lib/diarize/speaker.rb', line 50 def self.find_or_create(uri, gender) return @@speakers[uri] if @@speakers[uri] @@speakers[uri] = Speaker.new(uri, gender) end |
.load_model(filename) ⇒ Object
46 47 48 |
# File 'lib/diarize/speaker.rb', line 46 def self.load_model(filename) read_gmm(filename) end |
.match(speakers) ⇒ Object
82 83 84 |
# File 'lib/diarize/speaker.rb', line 82 def self.match(speakers) speakers.combination(2).select { |s1, s2| s1.same_speaker_as(s2) } end |
.match_sets(speakers1, speakers2) ⇒ Object
72 73 74 75 76 77 78 79 80 |
# File 'lib/diarize/speaker.rb', line 72 def self.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 |
.read_gmm(filename) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/diarize/speaker.rb', line 140 def self.read_gmm(filename) # gmmlist = java.util.ArrayList.new gmmlist = Rjb::JavaObjectWrapper.new("java.util.ArrayList") # input = fr.lium.spkDiarization.lib.IOFile.new(filename, 'rb') input = Rjb::import('fr.lium.spkDiarization.lib.IOFile').new(filename, 'rb') input.open # fr.lium.spkDiarization.libModel.ModelIO.readerGMMContainer(input, gmmlist) Rjb::import('fr.lium.spkDiarization.libModel.ModelIO').readerGMMContainer(input, gmmlist.java_object) input.close gmmlist.to_a.first.java_object end |
.ubm ⇒ Object
18 19 20 21 22 23 |
# File 'lib/diarize/speaker.rb', line 18 def self.ubm speaker = Speaker.new speaker.normalized = true speaker.model = Speaker.load_model(File.join(File.(File.dirname(__FILE__)), 'ubm.gmm')) speaker end |
Instance Method Details
#mean_log_likelihood ⇒ Object
25 26 27 |
# File 'lib/diarize/speaker.rb', line 25 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) ⇒ Object
29 30 31 |
# File 'lib/diarize/speaker.rb', line 29 def mean_log_likelihood=(mll) @mean_log_likelihood = mll end |
#namespaces ⇒ Object
122 123 124 |
# File 'lib/diarize/speaker.rb', line 122 def namespaces super.merge 'ws' => 'http://wsarchive.prototype0.net/ontology/' end |
#normalize! ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/diarize/speaker.rb', line 86 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 |
#rdf_mapping ⇒ Object
134 135 136 |
# File 'lib/diarize/speaker.rb', line 134 def rdf_mapping { 'ws:gender' => gender, 'ws:model' => model_uri, 'ws:mean_log_likelihood' => model.mean_log_likelihood, 'ws:supervector_hash' => supervector.hash.to_s } end |
#same_speaker_as(other) ⇒ Object
106 107 108 109 110 111 112 113 |
# File 'lib/diarize/speaker.rb', line 106 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) ⇒ Object
33 34 35 36 |
# File 'lib/diarize/speaker.rb', line 33 def save_model(filename) # TODO perhaps a warning if a normalised model is being saved? write_gmm(filename, @model) end |
#supervector ⇒ Object
115 116 117 118 |
# File 'lib/diarize/speaker.rb', line 115 def supervector # TODO: cache only when normalized @supervector ||= SuperVector.generate_from_model(model) end |
#type_uri ⇒ Object
130 131 132 |
# File 'lib/diarize/speaker.rb', line 130 def type_uri 'ws:Speaker' end |
#uri ⇒ Object
126 127 128 |
# File 'lib/diarize/speaker.rb', line 126 def uri @uri end |