# File "http://fonsg3.let.uva.nl/paul/papers/categ_learning3.praat" # Paul Boersma, June 23, 1998 # This Praat script performs the simulations of the learning of perceptual categorization, # as shown in: # Paul Boersma (1997): "Learning optionality, variation, and probability", # Rutgers Optimality Archive #221. [http://ruccs.rutgers.edu/roa.html] # This script also creates many pictures in the above paper # and if 'Save' is on, the script will write the pictures as Encapsulated PostScript files # to the same directory where the current script file resides, # giving them names like categ_learning_*.epsf. # The following default values generate figures 19, 21, 24, 25, and 29. # Changing the learning strategy to "Demotion only" and "Steps" to a million, # gives figures 19, 34, 35, and 36. # This file is version 3, with new script syntax. form Learning to categorize boolean Save 0 comment Production properties in acoustic units: positive Range_(acoustic_domain) 100 positive Step_(sampling_period) 0.5 positive Distance_(between_categories) 20 positive Spreading_(of_production) 10 comment Production property, relative: positive Markedness_(commonness) 3 comment Learning properties, in ranking units: positive Plasticity_(mean_demotion) 0.01 positive Safety_(ranking_spreading) 2.0 comment Other learning properties: boolean Spread_to_neighbours 1 choice Learning_strategy: 2 button Demotion only button Demotion/promotion comment Simulation of learning: natural Steps_(iteration_count) 100000 comment Simulation of perception experiment: natural Stimulus_replications 1000 endform let Promote = 'Learning_strategy' = 2 let Fsamp = 1/'Step' Erase all Times 10 Line width... 1 # Compute the averages. mu2 = 'Range'/2 mu1 = mu2-'Distance' mu3 = mu2+'Distance' ########## The production distributions ########## # Create the Gaussian distributions of the productions of the three categories. # The middle category is less common. Create Sound... dist1 0 'Range' 'Fsamp' 'Markedness'*exp(-(x-'mu1')^2/(2*'Spreading'^2)) Create Sound... dist2 0 'Range' 'Fsamp' exp(-(x-'mu2')^2/(2*'Spreading'^2)) Create Sound... dist3 0 'Range' 'Fsamp' 'Markedness'*exp(-(x-'mu3')^2/(2*'Spreading'^2)) # Draw the three distributions. Viewport... 0 5.4 0 2 Text top... yes Production distributions of the three categories /'mu1'/, /'mu2'/, and /'mu3'/. Text bottom... yes Produced acoustic value ceiling = 'Markedness'*1.1 select Sound dist1 Dotted line Draw... 0 'Range' 0 ceiling no select Sound dist2 Dashed line Draw... 0 'Range' 0 ceiling no Plain line select Sound dist3 Draw... 0 'Range' 0 ceiling no Draw inner box One mark bottom... mu1 yes yes no One mark bottom... mu2 yes yes no One mark bottom... mu3 yes yes no crit1 = (mu1+mu2)/2 + 'Spreading'^2*ln('Markedness')/'Distance' crit2 = (mu2+mu3)/2 - 'Spreading'^2*ln('Markedness')/'Distance' # Round to a single decimal (looks better in the picture than two decimals). crit1 = round(crit1*10)/10 crit2 = round(crit2*10)/10 One mark top... crit1 yes yes yes One mark top... crit2 yes yes yes Marks bottom... 2 yes yes no One mark left... 1 yes yes no One mark left... 'Markedness' yes yes no # Save picture. Viewport... 0.2 5 0 2 Text left... yes Frequency of occurrence if 'Save' Write picture to PostScript file... categ_learning_dist.epsf endif pause ########## The initial *WARP curves ########## # Compute the initial *WARP curves: all equally high. # They are parabolas, equal to -ln(dist). Create Sound... warp1 0 'Range' 'Fsamp' 0 Create Sound... warp2 0 'Range' 'Fsamp' 0 Create Sound... warp3 0 'Range' 'Fsamp' 0 call initialize_warp # Create a Gausssian demotion window. for i to 10 window'i' = exp(-i^2/20) endfor ;# A single large learning step? ;let x = 44 ;select Sound warp1 ;getnumber index = Get index from time... 'x' ;let index = round('index') ;let demotionStep = 0.3 ;let correctCandidate = 1 ;let winner = 2 ;call learningStep # Draw the three initial *WARP curves. if 'Save' Erase all endif Viewport... 0 5.4 2 4 Text top... yes A possible initial state (unbiased) call draw_warp One mark bottom... 44 yes yes yes inicrit1= (mu1+mu2)/2 One mark bottom... inicrit1 yes yes yes inicrit2 = (mu2+mu3)/2 One mark bottom... inicrit2 yes yes yes y = floor/2 x = inicrit1/2 Text... x Centre y Half /'mu1'/ x = (inicrit1+inicrit2)/2 Text... x Centre y Half /'mu2'/ x = (inicrit2+'Range')/2 Text... x Centre y Half /'mu3'/ # Save picture. Viewport... 0.2 5 2 4 Text left... yes Ranking if 'Save' Write picture to PostScript file... categ_learning_initial.epsf endif pause ########## The predicted response distributions ########## select Sound dist1 Copy... resp1 select Sound dist2 Copy... resp2 select Sound dist3 Copy... resp3 plus Sound resp1 plus Sound resp2 Formula... self / (Sound_dist1 [col] + Sound_dist2 [col] + Sound_dist3 [col]) if not 'Promote' if 'Save' Erase all endif Viewport... 5 10.4 4 6 # Demotion-only, incorrect version. select Sound dist1 Copy... dem1 Formula... 1-2*Sound_resp2[]*Sound_resp3[]/(Sound_resp1[]*Sound_resp2[]+Sound_resp1[]*Sound_resp3[]+Sound_resp2[]*Sound_resp3[]) Copy... dem2 Formula... 1-2*Sound_resp1[]*Sound_resp3[]/(Sound_resp1[]*Sound_resp2[]+Sound_resp1[]*Sound_resp3[]+Sound_resp2[]*Sound_resp3[]) Copy... dem3 Formula... 1-2*Sound_resp1[]*Sound_resp2[]/(Sound_resp1[]*Sound_resp2[]+Sound_resp1[]*Sound_resp3[]+Sound_resp2[]*Sound_resp3[]) Text top... no Behaviour of a demotion-only learner in equilibrium select Sound dem1 Dotted line Draw... 0 'Range' -1 1 no select Sound dem2 Dashed line Draw... 0 'Range' -1 1 no select Sound dem3 Plain line Draw... 0 'Range' -1 1 no Draw inner box Text bottom... yes Acoustic stimulus One mark bottom... mu1 yes yes no One mark bottom... mu2 yes yes no One mark bottom... mu3 yes yes no One mark top... crit1 no yes yes One mark top... crit2 no yes yes Marks bottom... 2 yes yes no Marks left every... 0.01 100 yes yes yes Viewport... 5.2 10 4 6 Text left... yes Percentage if 'Save' Write picture to PostScript file... categ_learning_negprob.epsf endif # Clip at zero. select Sound dem1 plus Sound dem2 plus Sound dem3 Formula... if self<0 then 0 else self fi # Probability-matching in zero regions. select Sound resp1 Formula... if Sound_dem3[]=0 then Sound_dist1[] / (Sound_dist1[] + Sound_dist2[]) else Sound_dem1[] fi select Sound resp2 Formula... if Sound_dem1[]=0 or Sound_dem3[]=0 then Sound_dist2[] / (Sound_dist1[] + Sound_dist2[] + Sound_dist3[]) else Sound_dem2[] fi select Sound resp3 Formula... if Sound_dem1[]=0 then Sound_dist3[] / (Sound_dist2[] + Sound_dist3[]) else Sound_dem3[] fi endif if 'Save' Erase all endif Viewport... 0 5.4 4 6 # Draw the three response distributions. if 'Promote' Text top... yes Demotion/promotion learner is predicted to match production probabilities else Text top... yes Predicted behaviour of demotion-only learner endif call draw_responses # Measure response frequency in percent units. Marks left every... 0.01 50 yes yes yes Viewport... 0.2 5 4 6 Text left... yes Percentage if 'Save' Write picture to PostScript file... categ_learning_predresp.epsf endif pause ########## The learning of *WARP ########## call initialize_warp for i to 'Steps' # Choose a category at random, taking into account # the relative markedness of the middle category. repeat producedCategory = randomInteger (1,3) until producedCategory <> 2 or randomUniform (0, 1) < 1/'Markedness' # Extract a realization from the chosen distribution. mu = mu'producedCategory' repeat x = randomGauss (mu, 'Spreading'); a Gausian distribution until x >= 1 and x <= 'Range' # Convert from the acoustic value (in 0..Range) to the index (in 1..Range/Step). select Sound warp1 index = Get index from time... x index = round(index) # Categorize the realization into the category with the lowest local *WARP value. # Get ranking values. select Sound warp1 r1 = Get value at index... index select Sound warp2 r2 = Get value at index... index select Sound warp3 r3 = Get value at index... index # Compute disharmonies: add categorization error (stochastic OT evaluation). d1 = randomGauss(r1,'Safety') d2 = randomGauss(r2,'Safety') d3 = randomGauss(r3,'Safety') # Recognize into minimum (traditional OT evaluation step). recognizedCategory = if d2 < d1 then if d3 < d2 then 3 else 2 fi else if d3 < d1 then 3 else 1 fi fi # Learn (error-driven, demotion-only: the Minimal Gradual Learning Algorithm). if recognizedCategory <> producedCategory ; Error? correctCandidate = producedCategory winner = recognizedCategory demotionStep = 'Plasticity'*(1+randomGauss(0,0.1)) call learningStep endif endfor # Draw the learned *WARP curves. if 'Save' Erase all endif Viewport... 0 5.4 6 8 Text top... yes Learned categorization after exposure to 'Steps' data. call draw_warp One mark bottom... crit1 no yes yes One mark bottom... crit2 no yes yes Viewport... 0.2 5 6 8 Text left... yes Ranking if 'Save' Write picture to PostScript file... categ_learning_final.epsf endif ########## The response distributions ########## call initialize_responses numberOfIndices = 'Range' * 'Fsamp' for index to numberOfIndices select Sound warp1 x = Get time from index... index for stimulus to 'Stimulus_replications' # Categorize the realization into the category with the lowest local *WARP value. select Sound warp1 v1 = Get value at index... index select Sound warp2 v2 = Get value at index... index select Sound warp3 v3 = Get value at index... index # Add categorization error (stochastic OT evaluation). v1 = v1 + randomGauss (0, 'Safety') v2 = v2 + randomGauss (0, 'Safety') v3 = v3 + randomGauss (0, 'Safety') # Recognize into minimum (traditional OT evaluation step). response = if v2 < v1 then if v3 < v2 then 3 else 2 fi else if v3 < v1 then 3 else 1 fi fi # Update response counter. select Sound resp'response' getnumber v = Get value at index... index v = v+1 Set value at index... index v endfor endfor # Normalize select Sound resp1 plus Sound resp2 plus Sound resp3 Formula... self/'Stimulus_replications' if 'Save' Erase all endif Viewport... 0 5.4 8 10 call draw_responses # Measure response frequency in percent units. Marks left every... 0.01 50 yes yes yes # Save picture. Viewport... 0.2 5 8 10 Text left... yes Percentage if 'Save' Write picture to PostScript file... categ_learning_responses.epsf endif echo ########## Ready! ########## procedure demote demote_ranking = Get value at index... index Set value at index... index demote_ranking-demotionStep # Also demote some of the neighbours somewhat. if 'Spread_to_neighbours' for demote_distance to 10 demote_other = index - demote_distance demote_ranking = Get value at index... demote_other Set value at index... demote_other demote_ranking-demotionStep*window'demote_distance' demote_other = index + demote_distance demote_ranking = Get value at index... demote_other Set value at index... demote_other demote_ranking-demotionStep*window'demote_distance' endfor endif endproc procedure learningStep # Demote the offender! select Sound warp'correctCandidate' call demote if 'Promote' select Sound warp'winner' demotionStep = -demotionStep call demote demotionStep = -demotionStep endif endproc procedure initialize_warp select Sound warp1 Formula... (x-'mu1')^2/(2*'Spreading'^2) select Sound warp2 Formula... (x-'mu2')^2/(2*'Spreading'^2) select Sound warp3 Formula... (x-'mu3')^2/(2*'Spreading'^2) endproc procedure draw_warp_legend Axes... 0 100 0 10 Dotted line Draw line... 0 11 6 11 Text... 6 Left 11 Half *W\s{ARP} (%x, /'mu1'/) Dashed line Draw line... 36 11 42 11 Text... 42 Left 11 Half *W\s{ARP} (%x, /'mu2'/) Plain line Draw line... 72 11 78 11 Text... 78 Left 11 Half *W\s{ARP} (%x, /'mu3'/) endproc procedure draw_warp call draw_warp_legend Text bottom... yes Acoustic input %x floor = -7 ceiling = 5 select Sound warp1 Dotted line Draw clipped... 0 'Range' floor ceiling no select Sound warp2 Dashed line Draw clipped... 0 'Range' floor ceiling no Plain line select Sound warp3 Draw clipped... 0 'Range' floor ceiling no Draw inner box One mark bottom... mu1 yes yes no One mark bottom... mu2 yes yes no One mark bottom... mu3 yes yes no Marks bottom... 2 yes yes no One mark left... floor yes yes no One mark left... 0 yes yes no One mark left... ceiling yes yes no endproc procedure initialize_responses select Sound resp1 plus Sound resp2 plus Sound resp3 Formula... 0 endproc procedure draw_responses_legend Axes... 0 100 0 10 Dotted line Draw line... 0 11 6 11 Text... 6 Left 11 Half \% /'mu1'/ responses Dashed line Draw line... 36 11 42 11 Text... 42 Left 11 Half \% /'mu2'/ responses Plain line Draw line... 72 11 78 11 Text... 78 Left 11 Half \% /'mu3'/ responses endproc procedure draw_responses call draw_responses_legend select Sound resp1 Dotted line Draw... 0 'Range' 0 1 no select Sound resp2 Dashed line Draw... 0 'Range' 0 1 no select Sound resp3 Plain line Draw... 0 'Range' 0 1 no Draw inner box Text bottom... yes Acoustic stimulus One mark bottom... mu1 yes yes no One mark bottom... mu2 yes yes no One mark bottom... mu3 yes yes no One mark top... crit1 no yes yes One mark top... crit2 no yes yes Marks bottom... 2 yes yes no endproc