ã¯ããã« ããã«ã¡ã¯ãITãœãªã¥ãŒã·ã§ã³éšïŒããžã¿ã«ãã¯ãããžãŒæŠç¥æ¬éšïŒã®S.Dã§ãã ä»åã¯å°æ£AIãèªåã§äœã£ãŠã¿ãã®ã§ãšã³ãžãã¢ããã°ã§ç޹ä»ããŸãïŒç®æšã¯ã æ£èããŒã¿ãåŠç¿ãããŠãå®éã«å¯Ÿå±ã§ããïŒã«ãŒã«ã«éåããªãïŒããã«ãããããš ãšããŸãã ç°å¢ã¯ä»¥äžã§æ§ç¯ããŸããã ç°å¢ ããŒãžã§ã³ OS Windows Pro 64bit CPU Ryzen 3900X GPU Geforce RTX2060Super Python 3.8.5 CUDA 10.1 cuDNN 7.6.5 Chainer 7.7.0 python-shogi 1.0.10 ãã®èšäºã§ã¯Pytorch ã§ã¯ãªã Chainerã䜿çšããŸããPytochã§ããæ§ç¯å¯èœã§ãããŸããå¥ã®æ©äŒãããã°Pytorchã§å®è£
ãããã®ãã玹ä»ã§ããã°ãšæããŸãã §0. ç°å¢æ§ç¯ ãã®ç« ã§ã¯ãç°å¢æ§ç¯ãããŸãã 0.1 Visual Studio ãã«ãããŒã« 2015ã®ã€ã³ã¹ããŒã« çŸç¶ã®ææ°ã®Visual Studioã¯ã2019ã§ããã2019ã§ã¯æ£åžžã«åäœããªãå ±åãå€ãã®ã§2015ãã€ã³ã¹ããŒã«ããŸãã Microsoft Build Tools 2015 Update 3ããããã€ã³ã¹ããŒã©ãããŠã³ããŒãã§ããŸãã 0.2 CUDAã®ã€ã³ã¹ããŒã« NVIDIA ããã€ã³ã¹ããŒã©ãããŠã³ããŒãã§ããŸãã 2020.11.24æç¹ã§ãææ°ããŒãžã§ã³ã¯11.1ã§ãã ãããã䜿çšãããœãããŠã§ã¢ã«å¯Ÿå¿ããããŒãžã§ã³ãã€ã³ã¹ããŒã«ããŸãã çŸç¶TensorFlowãChainerãªã©ã察å¿ããããŒãžã§ã³ã¯ã10.0, 10.1, (10.2)ã§ãã ç§ã¯ã10.1ãã€ã³ã¹ããŒã«ããŸããã 0.3 cuDNNã®ã€ã³ã¹ããŒã« NVIDIA ãããzipãã¡ã€ã«ãããŠã³ããŒãã§ããŸãã 2020.11.24æç¹ã§ãææ°ããŒãžã§ã³ã¯8.0.5ã§ãã ãããã䜿çšãããœãããŠã§ã¢ã«å¯Ÿå¿ããããŒãžã§ã³ãããŠã³ããŒãããŸãã çŸç¶TensorFlowãChainerãªã©ã察å¿ããããŒãžã§ã³ã¯ã7.6以å(8.0以éããã¶ã倧äžå€«)ã§ãã ç§ã¯ã7.6.5ã§åãããŠããŸãã ãã¡ã€ã«ãè§£åããããNVIDIA GPU Computing Toolkitã«ãã¡ã€ã«ãã³ããŒããŸã ç§ã®å Žåã¯ã C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1 ã«ãã¡ã€ã«ãã³ããŒããŸããã ç»åã«ããããã¡ã€ã«ãšãã©ã«ããã³ããŒããŠãäžã®ãã©ã«ãã«ç§»ããŸãã 0.4 Chainerã®ã€ã³ã¹ããŒã« Chainer ãã€ã³ã¹ããŒã«ããŸãã Chainerã¯ãæ©æ¢°åŠç¿ã®Pythonãã¬ãŒã ã¯ãŒã¯ã§ããæ¥æ¬äŒæ¥ã®æ ªåŒäŒç€ŸPreferred Networksããç ç©¶ãéçºãããŸãããçŸåšã¯ãFaceBookã®Pythonãã¬ãŒã ã¯ãŒã¯ã§ãããPytorchã«åžåãããŸããã 0.4.0 Pythonã®ã€ã³ã¹ããŒã« Python ã®ã€ã³ã¹ããŒã« ä»åã¯ãPythonã¯çç¥ããŸãã Pythonã¯ã3.6以éã3.8ãŸã§ã§ããã°æ£åžžã«åäœããŸãã Anacondaã§ã倧äžå€«ã§ãã 0.4.1 ãã®ä»ã¢ãžã¥ãŒã« pip install -U pip setuptools pip install -U jupyterlab jupyter jupyter-console jupytext spyder matplotlib numpy 0.4.2 Cupyã®ã€ã³ã¹ããŒã« Chainerã§ãGPUã䜿çšããããã«ã¯ãCupyãã€ã³ã¹ããŒã«ããå¿
èŠããããŸãã pip install cupy-cuda101 確èª: ãšã©ãŒãåºãªããã°å€§äžå€«ã§ãã ãšã©ãŒãåºãå ŽåãCuPyã®ã€ã³ã¹ããŒã«ãããŸãã§ããŠããªãã§ããæ±äº¬å€§åŠ éåç 究宀 ã«è©³ããæžããŠããã®ã§ããšã©ãŒãåºãŠé²ããªãå Žåã¯åèã«ããŠãã ããã 0.4.3 Chainerã®ã€ã³ã¹ããŒã« pip install chainer==7.7 0.4.4 Chainerã®åäœç¢ºèª Chainerã®Github ããããµã³ãã«ãèœãšããŠããŸãã cd chainer-7.7.0 python examples\mniost\train_mnist.py -g 0 ãªãã·ã§ã³ã¯ãgpuã®çªå·ã§ãã-1ã§ãgpuã䜿ããã«èšç®ã§ããŸãã 0.5 åŠç¿ããŒã¿ æ±äº¬å€§åŠå
ã®ãµãŒããŒãå°æ£ã³ã³ãã¥ãŒã¿å¯Ÿå±å Ž(Flood gate)ã®ããŒã¿ã䜿ããŸãã åŸã®ãã¥ãŒã©ã«ãããã¯ãŒã¯ãåŠç¿ãããããã®æ£èãçšæããŸãã ä»åã¯ããFlood gateãããææ°ã®2020幎ã®å
šæ£èããŒã¿ãcsa圢åŒã§èœãšããŸãã http://wdoor.c.u-tokyo.ac.jp/shogi/x/wdoor2017.7z äžã¯ã2017å¹Žã®æ£èããŒã¿ã§ããã(webãµã€ãæŽæ°ãããŠããªã),2017â2020ã«ããã°èœãšããŸãã(æžããŠããã®ãâŠ?) http://wdoor.c.u-tokyo.ac.jp/shogi/x/wdoor2020.7z 7zipã§è§£åããŠãã ããã å
šæ£è: 13äžä»¶ããã(çŸç¶ãªã®ã§ãä»ãå¢ããŠããŸã) ãã®ããšãåŠç¿ããŒã¿ãšããŠé©åã§ãªãããŒã¿ãããããããã®ã§ãææ°ã50æä»¥äžã§ãã¬ãŒãã£ã³ã°ã3000以äžã®ãã®ã«éå®ããŠãåŠç¿ããŒã¿ãšããŸããããã蟺ã¯ãã©ããªæ¹æ³ã§ãããã§ãã §1. ãã¥ãŒã©ã«ãããã¯ãŒã¯ ããããã¯ãæèéšåãå®è£
ããŸãã å
·äœçã«ãå±é¢ããæãæãäºæž¬ããããã«ããŸãã ã³ãŒãæ§æ \ïŒpolicynetworkïŒ(root dir) | setup.py | train_policy.py | kifulist_train.txt | kifulist_test.txt | kifulist_train_1000.txt | kifulist_test_100.txt |- ïŒmodelïŒ | | model_policy | |- ïŒpydlshogiïŒ | | common.py | | features.py | | read_kifu_.py | | | |- ïŒnetwork> | | policy.py | |- ïŒutilsïŒ | | fileter_csa.py | | make_kifu_list.py | | plot_log.py 1.1 ã¢ãžã¥ãŒã«ã€ã³ã¹ããŒã« import setuptoolssetuptools.setup( name = 'python-dlshogi', version = '0.0.1', author = 'SudaDaisuke', # åå packages = ['pydlshogi'], scripts = [],) ã¹ã¯ãªãããå¥ã®ã¹ã¯ãªãããããimportã§ããããã«ç»é²ããŸãã ãããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã§äžã®ã³ãã³ããæã¡ãŸãã pip install --no-cache-dir -e . 1.2 Policy Network å°æ£ã®æãæãäºæž¬ããããã®ããã¥ãŒã©ã«ãããã¯ãŒã¯ãæ§æããŸãã Alpha Go ã§ã¯ãæã¡æãæ¢çŽ¢ãããPolicy Networkããšå±é¢ãè©äŸ¡ãããValue NetworkããšããïŒã€ã®æ·±å±€ãã¥ãŒã©ã«ãããã¯ãŒã¯ã§æ§æãããŠããŸãã å°æ£ã®æãæãäºæž¬ããããã«ã Alpha Go ã§æ¡çšãããæ¹æ³ãæ¹è¯ããŠã13å±€ã®ç³ã¿èŸŒã¿ãã¥ãŒã©ã«ãããã¯ãŒã¯ãæ§æããŸãã ãã¥ãŒã©ã«ãããã¯ãŒã¯ã®ä»æ§ é
ç® å€ ãã£ã«ã¿ãŒãµã€ãº 3x3 äžéå±€ã®ãã£ã«ã¿ãŒãµã€ãº 192 ã¹ãã©ã€ã 1 ããã£ã³ã°å±€ 1 ããŒãªã³ã°å±€ 1 掻æ§å颿° ReLU 1.3 Policy Network å®è£
äžã®èšèšãããšã«å®è£
ããŠãããŸãã pydlshogi\network\policy.pyfrom chainer import Chainimport chainer.functions as Fimport chainer.links as Lfrom pydlshogi.common import *ch = 192class PolicyNetwork(Chain): def __init__(self): super(PolicyNetwork, self).__init__() with self.init_scope(): self.l1=L.Convolution2D(in_channels = 104, out_channels = ch, ksize = 3, pad = 1) self.l2=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l3=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l4=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l5=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l6=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l7=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l8=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l9=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l10=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l11=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l12=L.Convolution2D(in_channels = ch, out_channels = ch, ksize = 3, pad = 1) self.l13=L.Convolution2D(in_channels = ch, out_channels = MOVE_DIRECTION_LABEL_NUM, ksize = 1, nobias = True) self.l13_bias=L.Bias(shape=(9*9*MOVE_DIRECTION_LABEL_NUM)) def __call__(self, x): h1 = F.relu(self.l1(x)) h2 = F.relu(self.l2(h1)) h3 = F.relu(self.l3(h2)) h4 = F.relu(self.l4(h3)) h5 = F.relu(self.l5(h4)) h6 = F.relu(self.l6(h5)) h7 = F.relu(self.l7(h6)) h8 = F.relu(self.l8(h7)) h9 = F.relu(self.l9(h8)) h10 = F.relu(self.l10(h9)) h11 = F.relu(self.l11(h10)) h12 = F.relu(self.l12(h11)) h13 = self.l13(h12) return self.l13_bias(F.reshape(h13, (-1, 9*9*MOVE_DIRECTION_LABEL_NUM))) 1.2 åŠç¿åŠç 1.2.1 å®è£
train_policy.pyimport numpy as npimport chainerfrom chainer import cuda, Variablefrom chainer import optimizers, serializersimport chainer.functions as Ffrom pydlshogi.common import *from pydlshogi.network.policy import PolicyNetworkfrom pydlshogi.features import *from pydlshogi.read_kifu import *import argparseimport randomimport pickleimport osimport reimport loggingparser = argparse.ArgumentParser()parser.add_argument('kifulist_train', type=str, help='train kifu list')parser.add_argument('kifulist_test', type=str, help='test kifu list')parser.add_argument('--batchsize', '-b', type=int, default=32, help='Number of positions in each mini-batch')parser.add_argument('--test_batchsize', type=int, default=512, help='Number of positions in each test mini-batch')parser.add_argument('--epoch', '-e', type=int, default=1, help='Number of epoch times')parser.add_argument('--model', type=str, default='model/model_policy', help='model file name')parser.add_argument('--state', type=str, default='model/state_policy', help='state file name')parser.add_argument('--initmodel', '-m', default='', help='Initialize the model from given file')parser.add_argument('--resume', '-r', default='', help='Resume the optimization from snapshot')parser.add_argument('--log', default=None, help='log file path')parser.add_argument('--lr', type=float, default=0.01, help='learning rate')parser.add_argument('--eval_interval', '-i', type=int, default=1000, help='eval interval')args = parser.parse_args()logging.basicConfig(format='%(asctime)s\t%(levelname)s\t%(message)s', datefmt='%Y/%m/%d %H:%M:%S', filename=args.log, level=logging.DEBUG)model = PolicyNetwork()model.to_gpu()optimizer = optimizers.SGD(lr=args.lr)optimizer.setup(model)# Init/Resumeif args.initmodel: logging.info('Load model from {}'.format(args.initmodel)) serializers.load_npz(args.initmodel, model)if args.resume: logging.info('Load optimizer state from {}'.format(args.resume)) serializers.load_npz(args.resume, optimizer)logging.info('read kifu start')# ä¿åæžã¿ã®pickleãã¡ã€ã«ãããå Žåãpickleãã¡ã€ã«ãèªã¿èŸŒã# train datetrain_pickle_filename = re.sub(r'\..*?$', '', args.kifulist_train) + '.pickle'if os.path.exists(train_pickle_filename): with open(train_pickle_filename, 'rb') as f: positions_train = pickle.load(f) logging.info('load train pickle')else: positions_train = read_kifu(args.kifulist_train)# test datatest_pickle_filename = re.sub(r'\..*?$', '', args.kifulist_test) + '.pickle'if os.path.exists(test_pickle_filename): with open(test_pickle_filename, 'rb') as f: positions_test = pickle.load(f) logging.info('load test pickle')else: positions_test = read_kifu(args.kifulist_test)# ä¿åæžã¿ã®pickleããªãå Žåãpickleãã¡ã€ã«ãä¿åããif not os.path.exists(train_pickle_filename): with open(train_pickle_filename, 'wb') as f: pickle.dump(positions_train, f, pickle.HIGHEST_PROTOCOL) logging.info('save train pickle')if not os.path.exists(test_pickle_filename): with open(test_pickle_filename, 'wb') as f: pickle.dump(positions_test, f, pickle.HIGHEST_PROTOCOL) logging.info('save test pickle')logging.info('read kifu end')logging.info('train position num = {}'.format(len(positions_train)))logging.info('test position num = {}'.format(len(positions_test)))# mini batchdef mini_batch(positions, i, batchsize): mini_batch_data = [] mini_batch_move = [] for b in range(batchsize): features, move, win = make_features(positions[i + b]) mini_batch_data.append(features) mini_batch_move.append(move) return (Variable(cuda.to_gpu(np.array(mini_batch_data, dtype=np.float32))), Variable(cuda.to_gpu(np.array(mini_batch_move, dtype=np.int32))))def mini_batch_for_test(positions, batchsize): mini_batch_data = [] mini_batch_move = [] for b in range(batchsize): features, move, win = make_features(random.choice(positions)) mini_batch_data.append(features) mini_batch_move.append(move) return (Variable(cuda.to_gpu(np.array(mini_batch_data, dtype=np.float32))), Variable(cuda.to_gpu(np.array(mini_batch_move, dtype=np.int32))))# trainlogging.info('start training')itr = 0sum_loss = 0for e in range(args.epoch): positions_train_shuffled = random.sample(positions_train, len(positions_train)) itr_epoch = 0 sum_loss_epoch = 0 for i in range(0, len(positions_train_shuffled) - args.batchsize, args.batchsize): x, t = mini_batch(positions_train_shuffled, i, args.batchsize) y = model(x) model.cleargrads() loss = F.softmax_cross_entropy(y, t) loss.backward() optimizer.update() itr += 1 sum_loss += loss.data itr_epoch += 1 sum_loss_epoch += loss.data # print train loss and test accuracy if optimizer.t % args.eval_interval == 0: x, t = mini_batch_for_test(positions_test, args.test_batchsize) y = model(x) logging.info('epoch = {}, iteration = {}, loss = {}, accuracy = {}'.format(optimizer.epoch + 1, optimizer.t, sum_loss / itr, F.accuracy(y, t).data)) itr = 0 sum_loss = 0 # validate test data logging.info('validate test data') itr_test = 0 sum_test_accuracy = 0 for i in range(0, len(positions_test) - args.batchsize, args.batchsize): x, t = mini_batch(positions_test, i, args.batchsize) y = model(x) itr_test += 1 sum_test_accuracy += F.accuracy(y, t).data logging.info('epoch = {}, iteration = {}, train loss avr = {}, test accuracy = {}'.format(optimizer.epoch + 1, optimizer.t, sum_loss_epoch / itr_epoch, sum_test_accuracy / itr_test)) optimizer.new_epoch()logging.info('save the model')serializers.save_npz(args.model, model)logging.info('save the optimizer')serializers.save_npz(args.state, optimizer) äžã®ã³ãŒãã¯ãåŠç¿éšåãå®è£
ããŠããŸãã å
·äœçã«ã ãããªæãã«å®è£
ãããŠããŸãã 1.2.2 åŠç¿å®è¡ å®éã«åŠç¿ãå®è¡ãããšããããªæãã§ãæå€±èšç®ãšãåŠç¿ããŒã¿ããåŸãããçµæãšã®ç²ŸåºŠã§ãã §2. å°æ£AIå®è£
ãã¥ãŒã©ã«ãããã¯ãŒã¯ã§ãåŠç¿ãçµããã¢ãã«ã䜿ã£ãŠå¯Ÿå±ã§ããããã«ãUSIãšã³ãžã³ã«ããŸãã USI(Universal Shogi Interface)ãããã³ã«ãšã¯ãå°æ£GUIãœãããšæèãšã³ãžã³ãéä¿¡ãããããã«ãTord Romstadæ°ã«ãã£ãŠèæ¡ãããéä¿¡ãããã³ã«ã§ãã http://shogidokoro.starfree.jp/usi.html äžã®ããã«ãUSIãããã³ã«ãããšã«éä¿¡ããããšã§ãå°æ£AIãGUIäžã§åãããŸãã ãã©ã«ãæ§æ \ïŒpolicynetworkïŒ(root dir) |- ïŒbatïŒ | | Docbase.bat | |- ïŒpydlshogiïŒ | |- ïŒplayerïŒ | | base_player.py | | Docbase_player.py | | | |- ïŒusiïŒ | | usi.py | | usi_Docbase_player.py import numpy as npimport chainerfrom chainer import serializersfrom chainer import cuda, Variableimport chainer.functions as Fimport shogifrom pydlshogi.common import *from pydlshogi.features import *from pydlshogi.network.policy import *from pydlshogi.player.base_player import *def greedy(logits): return logits.index(max(logits))def boltzmann(logits, temperature): logits /= temperature logits -= logits.max() probabilities = np.exp(logits) probabilities /= probabilities.sum() return np.random.choice(len(logits), p=probabilities)class PolicyPlayer(BasePlayer): def __init__(self): super().__init__() self.modelfile = r'åŠç¿ããã¢ãã«ã®ãã¹' self.model = None def usi(self): print('id name DocBase ShogiAI') print('option name modelfile type string default ' + self.modelfile) print('usiok') def setoption(self, option): if option[1] == 'modelfile': self.modelfile = option[3] def isready(self): if self.model is None: self.model = PolicyNetwork() self.model.to_gpu() serializers.load_npz(self.modelfile, self.model) print('readyok') def go(self): if self.board.is_game_over(): print('bestmove resign') return features = make_input_features_from_board(self.board) x = Variable(cuda.to_gpu(np.array([features], dtype=np.float32))) with chainer.no_backprop_mode(): y = self.model(x) logits = cuda.to_cpu(y.data)[0] probabilities = cuda.to_cpu(F.softmax(y).data)[0] # å
šãŠã®åæ³æã«ã€ã㊠legal_moves = [] legal_logits = [] for move in self.board.legal_moves: # ã©ãã«ã«å€æ label = make_output_label(move, self.board.turn) # åæ³æãšãã®æãæã®ç¢ºç(logits)ãæ ŒçŽ legal_moves.append(move) legal_logits.append(logits[label]) # 確çã衚瀺 print('info string {:5} : {:.5f}'.format(move.usi(), probabilities[label])) # 確çãæå€§ã®æãéžã¶(ã°ãªãŒãã£ãŒæŠç¥) selected_index = greedy(legal_logits) # 確çã«å¿ããŠæãéžã¶(ãœããããã¯ã¹æŠç¥) selected_index = boltzmann(np.array(legal_logits, dtype=np.float32), 0.5) bestmove = legal_moves[selected_index] print('bestmove', bestmove.usi()) äžã®ããã«ãAIã®æ
å ±ãå±é¢ããšã®æåæãèšç®ããŠãããŸãã §3. GUIãœããã§åãã äžã§äœã£ãã¢ãã«ãšå®éã«å¯Ÿå±ããŸãã GUIãœããã¯ããã€ããããŸããã å°æ£æ ã䜿çšããŸãã äžã®ããã«ãç»é²ããããšãã§ããŸãã §4. åè åè URL å°æ£AIã§åŠã¶ãã£ãŒãã©ãŒãã³ã° https://book.mynavi.jp/ec/products/detail/id=88752 Alpha Goã®è«æ https://www.nature.com/articles/nature16961 §5. çµããã« ãããã§ããããïŒ ç§ã¯ãããŒãã²ãŒã ãè¶£å³ã§å°æ£ãå²ç¢ããã§ã¹çããã¡ãã奜ãã§ãã ãã§ã¹ã¯ã1997幎ã«ãåœæã®ãã£ã³ããªã³ ÐaÑÑО ÐаÑпaÑПв ããããIBM瀟ã®ãã£ãŒããã«ãŒã«æããŸãããç§ããŸã çãŸããŠããªãæä»£ãããAI vs 人éã®æŠããå§ãŸã£ãŠããããšãç¥ã£ããšãã¯ã驿ããŸããããããŠãããš10幎ã¯äººéã«åãŠãªããšããããŠãããå²ç¢ã2016å¹Žã«æ äžä¹ ããããGoogleåäžã®Demis Hassabis ãããçããDeepMind瀟ã®Alpha Goã«æããŸããã ä»åã®å°æ£AIããAlpha Goãåèã«ããŠããŸãã ãããŠãå°æ£ã2010幎代ãããã£ãšãponanzaãšããããå°æ£ãœããã®åŒ·ãã¯æ³šç®ãããŠããŸãããponanzaã«ã¯ãã¢ã³ãã«ã«ãæ³ãæ¡çšãããŠããŸãããåœæãããå°æ£ããã§ãããponanzaãäžç®ãããŠããŠãåœæã®ç«çã§ããæž¡èŸºæãããšponanzaã®å
¬é察å±ãå¬ããããããŸãããïŒæž¡èŸºæç«ç(åœæ)ã®é転åã¡) 2016幎ã Alpha Goã®è«æ ãå
¬éããããšãããã«Alpha ZeroãšåŒã°ããå°æ£AIãèªçããŸãããçŸåšã®ãå°æ£çã¯è€äºè¡å€ª2å ãã¯ãããšããŠãè¥å¹Žäžä»£ãçé ã«ãäžä»£ãåããå°æ£AIãçšããç ç©¶ãçãã«ãªã£ãŠããŸãã ã³ã³ãã¥ãŒã¿å°æ£å€§äŒããéãããŠããŠãå°æ£AIã®åŒ·ããç«¶ã倧äŒããããŸãããã²ãä»åã®èšäºã«èå³ããã£ãæ¹ã¯BERTã§ãå°æ£AIãäœã£ãŠã¿ãŠãã ããïŒ https://www.youtube.com/watch?v=2Vl6Ao4GaSQ&t=853s