前提・実現したいこと
githubから以下のコードをダウンロードして実行したのですが、表題のエラーが発生し実行することができません。
Unicodeに関するエラーなのですが、解決方法を教えていただけないでしょうか。
[Github]ArmRobot
エラーの詳細を記述していきます。
ターミナル上で、上記のコードを実行した時、
"ArmRobot-MLmaster/python/unityagents/environment.py"ファイル内の138行目
"p = self._conn.recv(self._buffer_size).decode('utf-8')"にて下記のようなエラーメッセージが発生します。
デコードができないと怒られているようです。
こちらのエラーの対処法をご存知の方がおられたら教えていただけないでしょうか?
発生している問題・エラーメッセージ
line 138, in __init__ p = self._conn.recv(self._buffer_size).decode('utf-8') UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfe in position 63: invalid start byte
該当のソースコード
python
1import atexit 2import io 3import glob 4import json 5import logging 6import numpy as np 7import os 8import socket 9import subprocess 10import struct 11 12from .brain import BrainInfo, BrainParameters, AllBrainInfo 13from .exception import UnityEnvironmentException, UnityActionException, UnityTimeOutException 14from .curriculum import Curriculum 15 16from PIL import Image 17from sys import platform 18 19logging.basicConfig(level=logging.INFO) 20logger = logging.getLogger("unityagents") 21 22 23class UnityEnvironment(object): 24 def __init__(self, file_name, worker_id=0, 25 base_port=5005, curriculum=None, 26 seed=0, docker_training=False): 27 """ 28 Starts a new unity environment and establishes a connection with the environment. 29 Notice: Currently communication between Unity and Python takes place over an open socket without authentication. 30 Ensure that the network where training takes place is secure. 31 32 :string file_name: Name of Unity environment binary. 33 :int base_port: Baseline port number to connect to Unity environment over. worker_id increments over this. 34 :int worker_id: Number to add to communication port (5005) [0]. Used for asynchronous agent scenarios. 35 :param docker_training: Informs this class whether the process is being run within a container. 36 """ 37 38 atexit.register(self.close) 39 self.port = base_port + worker_id 40 self._buffer_size = 12000 41 self._version_ = "API-3" 42 self._loaded = False 43 self._open_socket = False 44 45 try: 46 # Establish communication socket 47 self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 48 self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 49 self._socket.bind(("localhost", self.port)) 50 self._open_socket = True 51 except socket.error: 52 self._open_socket = True 53 self.close() 54 raise socket.error("Couldn't launch new environment because worker number {} is still in use. " 55 "You may need to manually close a previously opened environment " 56 "or use a different worker number.".format(str(worker_id))) 57 58 cwd = os.getcwd() 59 file_name = (file_name.strip() 60 .replace('.app', '').replace('.exe', '').replace('.x86_64', '').replace('.x86', '')) 61 true_filename = os.path.basename(os.path.normpath(file_name)) 62 logger.debug('The true file name is {}'.format(true_filename)) 63 launch_string = None 64 if platform == "linux" or platform == "linux2": 65 candidates = glob.glob(os.path.join(cwd, file_name) + '.x86_64') 66 if len(candidates) == 0: 67 candidates = glob.glob(os.path.join(cwd, file_name) + '.x86') 68 if len(candidates) == 0: 69 candidates = glob.glob(file_name + '.x86_64') 70 if len(candidates) == 0: 71 candidates = glob.glob(file_name + '.x86') 72 if len(candidates) > 0: 73 launch_string = candidates[0] 74 75 elif platform == 'darwin': 76 candidates = glob.glob(os.path.join(cwd, file_name + '.app', 'Contents', 'MacOS', true_filename)) 77 if len(candidates) == 0: 78 candidates = glob.glob(os.path.join(file_name + '.app', 'Contents', 'MacOS', true_filename)) 79 if len(candidates) == 0: 80 candidates = glob.glob(os.path.join(cwd, file_name + '.app', 'Contents', 'MacOS', '*')) 81 if len(candidates) == 0: 82 candidates = glob.glob(os.path.join(file_name + '.app', 'Contents', 'MacOS', '*')) 83 if len(candidates) > 0: 84 launch_string = candidates[0] 85 elif platform == 'win32': 86 candidates = glob.glob(os.path.join(cwd, file_name + '.exe')) 87 if len(candidates) == 0: 88 candidates = glob.glob(file_name + '.exe') 89 if len(candidates) > 0: 90 launch_string = candidates[0] 91 if launch_string is None: 92 self.close() 93 raise UnityEnvironmentException("Couldn't launch the {0} environment. " 94 "Provided filename does not match any environments." 95 .format(true_filename)) 96 else: 97 logger.debug("This is the launch string {}".format(launch_string)) 98 # Launch Unity environment 99 if docker_training == False: 100 proc1 = subprocess.Popen( 101 [launch_string, 102 '--port', str(self.port), 103 '--seed', str(seed)]) 104 else: 105 """ 106 Comments for future maintenance: 107 xvfb-run is a wrapper around Xvfb, a virtual xserver where all 108 rendering is done to virtual memory. It automatically creates a 109 new virtual server automatically picking a server number `auto-servernum`. 110 The server is passed the arguments using `server-args`, we are telling 111 Xvfb to create Screen number 0 with width 640, height 480 and depth 24 bits. 112 Note that 640 X 480 are the default width and height. The main reason for 113 us to add this is because we'd like to change the depth from the default 114 of 8 bits to 24. 115 Unfortunately, this means that we will need to pass the arguments through 116 a shell which is why we set `shell=True`. Now, this adds its own 117 complications. E.g SIGINT can bounce off the shell and not get propagated 118 to the child processes. This is why we add `exec`, so that the shell gets 119 launched, the arguments are passed to `xvfb-run`. `exec` replaces the shell 120 we created with `xvfb`. 121 """ 122 docker_ls = ("exec xvfb-run --auto-servernum" 123 " --server-args='-screen 0 640x480x24'" 124 " {0} --port {1} --seed {2}").format(launch_string, 125 str(self.port), 126 str(seed)) 127 proc1 = subprocess.Popen(docker_ls, 128 stdout=subprocess.PIPE, 129 stderr=subprocess.PIPE, 130 shell=True) 131 self._socket.settimeout(30) 132 try: 133 try: 134 self._socket.listen(1) 135 self._conn, _ = self._socket.accept() 136 self._conn.settimeout(30) 137 import pdb; pdb.set_trace() 138#下記の行でエラーが発生します 139 p = self._conn.recv(self._buffer_size).decode('utf-8') 140 p = json.loads(p) 141 except socket.timeout as e: 142 raise UnityTimeOutException( 143 "The Unity environment took too long to respond. Make sure {} does not need user interaction to " 144 "launch and that the Academy and the external Brain(s) are attached to objects in the Scene." 145 .format(str(file_name))) 146#teratailの仕様上10000文字以上の投稿はできないようなので、これ以下のコードは省略します。お手数ですが、上記のリンクのgithubから参照ください 147
試したこと
・実行したシェルの文字コードの確認(echo $LANG)
ターミナルの文字コードはja_JP.UTF-8
ターミナルとコードの文字コードの不一致によるエラーの発生の線は薄そうです。
・デバッグ(pdb)
変数pには何も格納されていませんでした。
socketで送られてきたデータの中身を確認することは叶わず
・インターネットで調べてみるも解決方法に至るような情報は見つからず
python3でのbytes型の中で.decode('utf-8')を指定してもエラーになる
技術系メモ
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbc in position 0: invalid start byte
補足情報(FW/ツールのバージョンなど)
macOS Sierra 10.12.6
Unity 2018.2.4.f1
ターミナル2.7.3(文字コード ja_JP.UTF-8 )
Python 3.6.6 :: Anaconda, Inc.

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/08/24 06:30
2018/08/24 07:47
2018/08/24 08:58
2018/08/24 09:12