This is the Beta version of our User Manual and Datasets.
Feel free to contact Yisong if you have any questions to use our system. (miaoyisong [AT] gmail.com)
This is possibly the first open-source system for conversational recommendation in recent years.
Wish you find it helpful! 😛
Please kindly cite our paper if you use our codes or dataset.
@inproceedings{lei2020estimation,title={Estimation-Action-Reflection: Towards Deep Interaction Between Conversational and Recommender Systems},author={Lei, Wenqiang and He, Xiangnan and Miao, Yisong and Wu, Qingyun and Hong, Richang and Kan, Min-Yen and Chua, Tat-Seng},booktitle={Proceedings of the 13th International Conference on Web Search and Data Mining},pages={304--312},year={2020}}
Shortcuts:
Code:
xxxxxxxxxxwget https://yisong.me/publications/EAR.zip
Dataset:
xxxxxxxxxxhttps://drive.google.com/open?id=13WcWe9JthbiSjcGeCWSTB6Ir7O6riiYy
Table of Content:
EAR System -- User Manual and Datasets (Beta Version)1. System Overview1.1 Dependencies2. Datasets3. Estimation Stage -- Factorization Machine Model4. Action Stage & Reflection Stage -- User Simulator4.1 Action Stage Training and Evaluation4.2 Ablation Study4.3 Baselines5. Licence and Patent
TODO: Yisong: Need to draw an overview figure of our system here.
This system is developed in Python and PyTorch. It is composed of two components:
lib/FMlib/user-simulatorNote: Due to different settings in Yelp (enumerated questions) and LastFM (binary questions), their codes are stored in different directory with minor differences. However, the command lines below can be used interchangeably.
xwget https://yisong.me/publications/EAR.zip
Run following codes to have a quick check if you have all packages ready.
​xFirst clone EAR to your root directory​cd ~/EAR​python package-check.py
We currently put our data on Google Drive, please contact Yisong if you can't download it ( miaoyisong [AT] gmail.com).
Link:
xhttps://drive.google.com/open?id=13WcWe9JthbiSjcGeCWSTB6Ir7O6riiYy
All Functions of our FM model can be realized by changing the parameter in FM_old_train.py as shown below:
xxxxxxxxxx parser = argparse.ArgumentParser(description="Run FM") parser.add_argument('-lr', type=float, metavar='<lr>', dest='lr', help='lr') parser.add_argument('-flr', type=float, metavar='<flr>', dest='flr', help='flr') # means the learning rate of feature similarity learning parser.add_argument('-reg', type=float, metavar='<reg>', dest='reg', help='reg') # regularization parser.add_argument('-decay', type=float, metavar='<decay>', dest='decay', help='decay') # weight decay parser.add_argument('-qonly', type=int, metavar='<qonly>', dest='qonly', help='qonly') # means quadratic form only (letting go other terms in FM equation...) parser.add_argument('-bs', type=int, metavar='<bs>', dest='bs', help='bs') # batch size parser.add_argument('-hs', type=int, metavar='<hs>', dest='hs', help='hs') # hidden size parser.add_argument('-ip', type=float, metavar='<ip>', dest='ip', help='ip') # init parameter for hidden parser.add_argument('-dr', type=float, metavar='<dr>', dest='dr', help='dr') # dropout ratio parser.add_argument('-optim', type=str, metavar='<optim>', dest='optim', help='optim') # optimizer parser.add_argument('-observe', type=int, metavar='<observe>', dest='observe', help='observe') # the frequency of doing evaluation parser.add_argument('-oldnew', type=str, metavar='<oldnew>', dest='oldnew', help='oldnew') # we don't use this parameter now parser.add_argument('-pretrain', type=int, metavar='<pretrain>', dest='pretrain', help='pretrain') # does it need to load pretrain model? parser.add_argument('-uf', type=int, metavar='<uf>', dest='uf', help='uf') # update feature parser.add_argument('-rd', type=int, metavar='<rd>', dest='rd', help='rd') # remove duplicate, we don;t use this parameter now parser.add_argument('-useremb', type=int, metavar='<useremb>', dest='useremb', help='user embedding') # update user embedding during feature similarity parser.add_argument('-freeze', type=int, metavar='<freeze>', dest='freeze', help='freeze') # we don't use this param now parser.add_argument('-command', type=int, metavar='<command>', dest='command', help='command') # command = 6: normal FM # command = 8: with our second type of negative sample parser.add_argument('-seed', type=int, metavar='<seed>', dest='seed', help='seed') # random seed A = parser.parse_args()
The code to run experiment:
xxxxxxxxxx# Yelp has the slightly better overall performance with Adagrad Optimizer# LastFM would be better with SGD.# The differences are minor.​cd ~/EAR/yelp/lib/FM​#FM (basic FM)CUDA_VISIBLE_DEVICES=0 python FM_old_train.py -lr 0.01 -flr 0.001 -reg 0.002 -decay 0 -qonly 1 -bs 64 -hs 64 -ip 0.01 -dr 0.5 -optim Ada -observe 1 -oldnew new -pretrain 0 -rd 0 -uf 0 -freeze 0 -command 6 -useremb 1 -seed 330​#FM+A (FM and attribute aware BPR)CUDA_VISIBLE_DEVICES=1 python FM_old_train.py -lr 0.01 -flr 0.001 -reg 0.002 -decay 0 -qonly 1 -bs 64 -hs 64 -ip 0.01 -dr 0.5 -optim Ada -observe 1 -oldnew new -pretrain 0 -rd 0 -uf 0 -freeze 0 -command 8 -useremb 1 -seed 330​#FM+A+T (multi-task training for item recommendation and attribute prediction)python FM_old_train.py -lr 0.01 -flr 0.001 -reg 0.002 -decay 0 -qonly 1 -bs 64 -hs 64 -ip 0.01 -dr 0.5 -optim Ada -observe 1 -oldnew new -pretrain 2 -rd 0 -uf 1 -freeze 0 -command 8 -useremb 1 -seed 330-----------------------------------------------​cd ~/EAR/lastfm/lib/FM​#FMCUDA_VISIBLE_DEVICES=2 python FM_old_train.py -lr 0.01 -flr 0.001 -reg 0.002 -decay 0 -qonly 1 -bs 64 -hs 64 -ip 0.01 -dr 0.5 -optim SGD -observe 10 -oldnew new -pretrain 0 -rd 0 -uf 0 -freeze 0 -command 6 -useremb 1 -seed 330​#FM + ACUDA_VISIBLE_DEVICES=2 python FM_old_train.py -lr 0.01 -flr 0.001 -reg 0.002 -decay 0 -qonly 1 -bs 64 -hs 64 -ip 0.01 -dr 0.5 -optim SGD -observe 10 -oldnew new -pretrain 0 -rd 0 -uf 0 -freeze 0 -command 8 -useremb 1 -seed 330​#FM + A + MTpython FM_old_train.py -lr 0.01 -flr 0.001 -reg 0.002 -decay 0 -qonly 1 -bs 64 -hs 64 -ip 0.01 -dr 0.5 -optim SGD -observe 1 -oldnew new -pretrain 2 -rd 0 -uf 1 -freeze 0 -command 8 -useremb 1 -seed 330
Both Action Stage and Reflection Stage is implemented in the user-simulator directory.
This user simulator obeys our Multi-Round Conversational Recommendation Scenario, it can be easily customised to your own usage.
We have a user-friendly interface, you only need to change the parameter below in run.py to do all experiments.
xxxxxxxxxx parser = argparse.ArgumentParser(description="Run conversational recommendation.") parser.add_argument('-mt', type=int, dest='mt', help='MAX_TURN') parser.add_argument('-playby', type=str, dest='playby', help='playby') # options include: # AO: (Ask Only and recommend by probability) # RO: (Recommend Only) # policy: (action decided by our policy network) parser.add_argument('-fmCommand', type=str, dest='fmCommand', help='fmCommand') # the command used for FM, check out /EAR/lastfm/FM/ parser.add_argument('-optim', type=str, dest='optim', help='optimizer') # the optimizer for policy network parser.add_argument('-lr', type=float, dest='lr', help='lr') # learning rate of policy network parser.add_argument('-decay', type=float, dest='decay', help='decay') # weight decay parser.add_argument('-TopKTaxo', type=int, dest='TopKTaxo', help='TopKTaxo') # how many 2-layer feature will represent a big feature. Only Yelp dataset use this param, lastFM have no effect. parser.add_argument('-gamma', type=float, dest='gamma', help='gamma') # gamma of training policy network parser.add_argument('-trick', type=int, dest='trick', help='trick') # whether use normalization in training policy network parser.add_argument('-startFrom', type=int, dest='startFrom', help='startFrom') # startFrom which user-item interaction pair parser.add_argument('-endAt', type=int, dest='endAt', help='endAt') # endAt which user-item interaction pair parser.add_argument('-strategy', type=str, dest='strategy', help='strategy') # strategy to choose question to ask, only have effect parser.add_argument('-eval', type=int, dest='eval', help='eval') # whether current run is for evaluation parser.add_argument('-mini', type=int, dest='mini', help='mini') # means `mini`-batch update the FM parser.add_argument('-alwaysupdate', type=int, dest='alwaysupdate', help='alwaysupdate') # means always mini-batch update the FM, alternative is that only do the update for 1 time in a session. # we leave this exploration tof follower of our work. parser.add_argument('-initeval', type=int, dest='initeval', help='initeval') # whether do the evaluation for the `init`ial version of policy network (directly after pre-train) parser.add_argument('-upoptim', type=str, dest='upoptim', help='upoptim') # optimizer for reflection stafe parser.add_argument('-upcount', type=int, dest='upcount', help='upcount') # how many times to do reflection parser.add_argument('-upreg', type=float, dest='upreg', help='upreg') # regularization term in parser.add_argument('-code', type=str, dest='code', help='code') # We use it to give each run a unique identifier. parser.add_argument('-purpose', type=str, dest='purpose', help='purpose') # options: pretrain, others parser.add_argument('-mod', type=str, dest='mod', help='mod') # options: CRM, EAR parser.add_argument('-mask', type=int, dest='mask', help='mask') # use for ablation study, 1, 2, 3, 4 represent our four segments, {ent, sim, his, len}xxxxxxxxxxcd ~/EAR/yelp/lib/user-simulator​# TrainingCUDA_VISIBLE_DEVICES=1 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0.7 -strategy maxent -startFrom 0 -endAt 20000 -eval 0 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 1 -upreg 0.001 -code stable -mask 0 -purpose train -mod ear​# EvaluationCUDA_VISIBLE_DEVICES=2 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 0 -purpose train -mod earTo see how the systems works:
xxxxxxxxxxcd ~/EAR/statistics/​python conversation-evaluation.pyYou will see the printed results in this format:
xxxxxxxxxxtotal epi: 11891turn, 1, SR, 0.000turn, 2, SR, 0.000turn, 3, SR, 0.000turn, 4, SR, 0.003turn, 5, SR, 0.017turn, 6, SR, 0.043turn, 7, SR, 0.086turn, 8, SR, 0.135turn, 9, SR, 0.180turn, 10, SR, 0.227turn, 11, SR, 0.265turn, 12, SR, 0.304turn, 13, SR, 0.339turn, 14, SR, 0.371turn, 15, SR, 0.398average: 12.632
xxxxxxxxxxChange the `-mask` into 1, 2, 3, 4, for ablation study on segments of ent, sim, his, and len respectively​CUDA_VISIBLE_DEVICES=2 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 1 -purpose train -mod ear​CUDA_VISIBLE_DEVICES=0 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 2 -purpose train -mod ear​CUDA_VISIBLE_DEVICES=1 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 3 -purpose train -mod ear​CUDA_VISIBLE_DEVICES=2 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 4 -purpose train -mod earxxxxxxxxxxWe simply need to change ​CUDA_VISIBLE_DEVICES=1 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 0 -alwaysupdate 0 -upcount 0 -upreg 0.001 -code stable -mask 0 -purpose train -mod ear
All baselines can all be easily implemented in our user simulator.
xxxxxxxxxxCUDA_VISIBLE_DEVICES=0 python run.py -mt 15 -playby AO -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 0 -purpose train -mod ear
The training and Evaluation of this model can also be done following a simple mod parameter.
xxxxxxxxxx# TrainingCUDA_VISIBLE_DEVICES=1 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0.7 -strategy maxent -startFrom 0 -endAt 20000 -eval 0 -initeval 0 -trick 0 -mini 0 -alwaysupdate 0 -upcount 0 -upreg 0.001 -code stable -mask 0 -purpose train -mod crm​# EvaluationCUDA_VISIBLE_DEVICES=0 python run.py -mt 15 -playby policy -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 0 -purpose train -mod crmAbs-Greedy Algorithm can be easily realized through our system. It is equivalent to Recommending Only option plus Update mechanism.
xxxxxxxxxxCUDA_VISIBLE_DEVICES=0 python run.py -mt 15 -playby RO -optim SGD -lr 0.001 -fmCommand 8 -upoptim SGD -decay 0 -TopKTaxo 3 -gamma 0 -strategy maxent -startFrom 0 -endAt 20000 -eval 1 -initeval 0 -trick 0 -mini 1 -alwaysupdate 1 -upcount 4 -upreg 0.001 -code stable -mask 0 -purpose train -mod ear
TODO: Yisong