"""
			
			    finetune!(learner, nepochs[, base_lr = 0.002; kwargs...])
			
			Behaves like the fastai implementation
			[`fastai.Learner.fine_tune`](https://github.com/fastai/fastai/blob/master/fastai/callback/schedule.py#L151).
			
			## Keyword arguments
			
			- `freezeepochs = 1`: Number of epochs to train with the backbone completely frozen.
			- `grouper = FastAI.defaultgrouper(learner.model)`: [`ParamGrouper`](#) which assigns
			    groups `1` (backbone) or `2` (head) for every parameter in `learner.model`. The
			    default expects `learner.model` to be a `Chain(backbone, head)`.
			- `backbone_factor = 0.1`: Factor by which updates to backbone model are discounted
			    during the second phase of training.
			
			Any additional keyword arguments are passed to [`fitonecycle!`](#).
			"""
			
			
			function
			 
			
	
			finetune!
			(
			learner
			,
			
                   
			nepochs
			,
			
                   
			
			base_lr
			 
			=
			 
			0.002
			
			;
			
                   
			
			freezeepochs
			 
			=
			 
			1
			,
			
                   
			
			grouper
			 
			=
			 
			
	
			defaultgrouper
			(
			
			learner
			.
			
			model
			)
			,
			
                   
			
			backbone_factor
			 
			=
			 
			0.1
			,
			
                   
			
			div
			 
			=
			 
			5
			,
			
                   
			
			kwargs
			...
			)
			
			
			
    
			
    
			
			foptim
			 
			=
			 
			
	
			frozen_optimizer
			(
			
			learner
			.
			
			optimizer
			,
			 
			grouper
			,
			 
			
			learner
			.
			
			model
			)
			
    
			
			
	
			withfields
			(
			learner
			,
			 
			
			optimizer
			 
			=
			 
			foptim
			)
			 
			do
			
			
        
			
			
	
			fitonecycle!
			(
			learner
			,
			 
			freezeepochs
			,
			 
			base_lr
			,
			 
			
			pct_start
			 
			=
			 
			0.99
			
			;
			 
			
			kwargs
			...
			)
			
    
			end
			
			
    
			
    
			
			doptim
			 
			=
			 
			
	
			discrlr_optimizer
			(
			
			learner
			.
			
			optimizer
			,
			 
			grouper
			,
			 
			
			learner
			.
			
			model
			,
			 
			backbone_factor
			)
			
    
			
			
	
			withfields
			(
			learner
			,
			 
			
			optimizer
			 
			=
			 
			doptim
			)
			 
			do
			
			
        
			
			
	
			fitonecycle!
			(
			learner
			,
			 
			nepochs
			,
			 
			
			base_lr
			 
			/
			 
			2
			
			;
			
                     
			
			div
			 
			=
			 
			div
			,
			 
			
			kwargs
			...
			)
			
    
			end
			
			
    
			
			return
			 
			learner
			
			end
			
			
			
			
			
			"""
			
			    frozen_optimizer(optim, grouper, model)
			
			Create an optimizer that only updates parameters which [`ParamGrouper`](#)
			puts into group `2`.
			"""
			
			
			
	
			frozen_optimizer
			(
			optim
			,
			 
			grouper
			,
			 
			model
			)
			 
			=
			 
			
	
			discrlr_optimizer
			(
			optim
			,
			 
			grouper
			,
			 
			model
			,
			 
			0.0
			)
			
			
			
			
			
			"""
			
			    frozen_optimizer(optim, grouper, model, factor)
			
			Create an optimizer that discounts updates parameters which [`ParamGrouper`](#)
			puts into group `1` by `factor`.
			"""
			
			
			function
			 
			
	
			discrlr_optimizer
			(
			optim
			,
			 
			grouper
			,
			 
			model
			,
			 
			factor
			)
			
			
    
			
			paramgroups
			 
			=
			 
			
	
			ParamGroups
			(
			grouper
			,
			 
			model
			)
			
    
			
			return
			 
			
	
			Optimiser
			(
			
	
			DiscriminativeLRs
			(
			paramgroups
			,
			 
			
			Dict
			(
			
			1
			 
			=>
			 
			factor
			,
			 
			
			2
			 
			=>
			 
			1.0
			)
			)
			,
			
                     
			optim
			)
			
			end
			
			
			
			function
			 
			
	
			defaultgrouper
			(
			model
			)
			
			
    
			
			if
			 
			
			!
			(
			
			(
			
			model
			 
			isa
			 
	
			Chain
			)
			 
			&&
			
			 
			
			length
			(
			model
			)
			 
			==
			 
			2
			)
			
			
        
			
			error
			(
			
			"
			Cannot freeze `learner.model` automatically since it is not a `Chain`.
              Please provide a `ParamGrouper` with the `grouper` keyword argument.
              The `grouper` should assign groups `1` (backbone) and `2` (head).
              
			"
			)
			
    
			else
			
			
        
			
			return
			 
			
	
			IndexGrouper
			(
			
			[
			
			1
			:
			(
			
			
			length
			(
			model
			)
			 
			-
			 
			1
			)
			,
			 
			
			length
			(
			model
			)
			]
			)
			
    
			end
			
			end