imports

import numpy as np
import matplotlib.pyplot as plt 
import tensorflow as tf 
import tensorflow.experimental.numpy as tnp 
tnp.experimental_enable_numpy_behavior()
import graphviz
def gv(s): return graphviz.Source('digraph G{ rankdir="LR"'+s + '; }')

$x \to \hat{y}$ 가 되는 과정을 그림으로 그리기

- 단순회귀분석의 예시

  • $\hat{y}_i = \hat{\beta}_0 + \hat{\beta}_1 x_i, \quad i=1,2,\dots,n$

(표현1)

gv(''' 
    "1" -> "β̂₀ + xₙ*β̂₁,    bias=False"[label="* β̂₀"]
    "xₙ" -> "β̂₀ + xₙ*β̂₁,    bias=False"[label="* β̂₁"]
    "β̂₀ + xₙ*β̂₁,    bias=False" -> "ŷₙ"[label="identity"]

    "." -> "...................................."[label="* β̂₀"]
    ".." -> "...................................."[label="* β̂₁"]
    "...................................." -> "..."[label=" "]

    "1 " -> "β̂₀ + x₂*β̂₁,    bias=False"[label="* β̂₀"]
    "x₂" -> "β̂₀ + x₂*β̂₁,    bias=False"[label="* β̂₁"]
    "β̂₀ + x₂*β̂₁,    bias=False" -> "ŷ₂"[label="identity"]
    
    "1  " -> "β̂₀ + x₁*β̂₁,    bias=False"[label="* β̂₀"]
    "x₁" -> "β̂₀ + x₁*β̂₁,    bias=False"[label="* β̂₁"]
    "β̂₀ + x₁*β̂₁,    bias=False" -> "ŷ₁"[label="identity"]
''')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:79, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     78         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 79     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:99, in _run_input_lines(cmd, input_lines, kwargs)
     98 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 99     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
    101     stdin_write = popen.stdin.write

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:966, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)
    963             self.stderr = io.TextIOWrapper(self.stderr,
    964                     encoding=encoding, errors=errors)
--> 966     self._execute_child(args, executable, preexec_fn, close_fds,
    967                         pass_fds, cwd, env,
    968                         startupinfo, creationflags, shell,
    969                         p2cread, p2cwrite,
    970                         c2pread, c2pwrite,
    971                         errread, errwrite,
    972                         restore_signals,
    973                         gid, gids, uid, umask,
    974                         start_new_session)
    975 except:
    976     # Cleanup if the child failed starting.

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:1842, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1841         err_msg = os.strerror(errno_num)
-> 1842     raise child_exception_type(errno_num, err_msg, err_filename)
   1843 raise child_exception_type(err_msg)

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/IPython/core/formatters.py:973, in MimeBundleFormatter.__call__(self, obj, include, exclude)
    970     method = get_real_method(obj, self.print_method)
    972     if method is not None:
--> 973         return method(include=include, exclude=exclude)
    974     return None
    975 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in <dictcomp>(.0)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
    110 def _repr_image_svg_xml(self) -> str:
    111     """Return the rendered graph as SVG string."""
--> 112     return self.pipe(format='svg', encoding=SVG_ENCODING)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)
     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)
    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=2)
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)
    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    146 if encoding is not None:
    147     if codecs.lookup(encoding) is codecs.lookup(self.encoding):
    148         # common case: both stdin and stdout need the same encoding
--> 149         return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
    150     try:
    151         raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
    206 cmd = dot_command.command(engine, format,
    207                           renderer=renderer,
    208                           formatter=formatter,
    209                           neato_no_op=neato_no_op)
    210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    213 return proc.stdout

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:84, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:
---> 84         raise ExecutableNotFound(cmd) from e
     85     raise
     87 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<graphviz.sources.Source at 0x7f9cd4fa9540>

- 표현1의 소감?

  • 교수님이 고생해서 만든것 같음
  • 그런데 그냥 다 똑같은 그림의 반복이라 사실 고생한 의미가 없음.

(표현2)

- 그냥 아래와 같이 그리고 "모든 $i=1,2,3,\dots,n$에 대하여 $\hat{y}_i$을 아래의 그림과 같이 그린다"고 하면 될것 같다.

gv(''' 
    "1" -> "β̂₀ + xᵢ*β̂₁,    bias=False"[label="* β̂₀"]
    "xᵢ" -> "β̂₀ + xᵢ*β̂₁,    bias=False"[label="* β̂₁"]
    "β̂₀ + xᵢ*β̂₁,    bias=False" -> "ŷᵢ"[label="identity"]

''')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:79, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     78         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 79     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:99, in _run_input_lines(cmd, input_lines, kwargs)
     98 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 99     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
    101     stdin_write = popen.stdin.write

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:966, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)
    963             self.stderr = io.TextIOWrapper(self.stderr,
    964                     encoding=encoding, errors=errors)
--> 966     self._execute_child(args, executable, preexec_fn, close_fds,
    967                         pass_fds, cwd, env,
    968                         startupinfo, creationflags, shell,
    969                         p2cread, p2cwrite,
    970                         c2pread, c2pwrite,
    971                         errread, errwrite,
    972                         restore_signals,
    973                         gid, gids, uid, umask,
    974                         start_new_session)
    975 except:
    976     # Cleanup if the child failed starting.

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:1842, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1841         err_msg = os.strerror(errno_num)
-> 1842     raise child_exception_type(errno_num, err_msg, err_filename)
   1843 raise child_exception_type(err_msg)

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/IPython/core/formatters.py:973, in MimeBundleFormatter.__call__(self, obj, include, exclude)
    970     method = get_real_method(obj, self.print_method)
    972     if method is not None:
--> 973         return method(include=include, exclude=exclude)
    974     return None
    975 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in <dictcomp>(.0)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
    110 def _repr_image_svg_xml(self) -> str:
    111     """Return the rendered graph as SVG string."""
--> 112     return self.pipe(format='svg', encoding=SVG_ENCODING)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)
     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)
    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=2)
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)
    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    146 if encoding is not None:
    147     if codecs.lookup(encoding) is codecs.lookup(self.encoding):
    148         # common case: both stdin and stdout need the same encoding
--> 149         return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
    150     try:
    151         raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
    206 cmd = dot_command.command(engine, format,
    207                           renderer=renderer,
    208                           formatter=formatter,
    209                           neato_no_op=neato_no_op)
    210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    213 return proc.stdout

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:84, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:
---> 84         raise ExecutableNotFound(cmd) from e
     85     raise
     87 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<graphviz.sources.Source at 0x7f9cd49c2830>

(표현3)

- 그런데 "모든 $i=1,2,3,\dots,n$에 대하여 $\hat{y}_i$을 아래의 그림과 같이 그린다" 라는 언급자체도 반복할 필요가 없을 것 같다. (어차피 당연히 그럴테니까) 그래서 단순히 아래와 같이 그려도 무방할듯 하다.

gv(''' 
    "1" -> "β̂₀ + x*β̂₁,    bias=False"[label="* β̂₀"]
    "x" -> "β̂₀ + x*β̂₁,    bias=False"[label="* β̂₁"]
    "β̂₀ + x*β̂₁,    bias=False" -> "ŷ"[label="identity"]

''')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:79, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     78         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 79     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:99, in _run_input_lines(cmd, input_lines, kwargs)
     98 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 99     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
    101     stdin_write = popen.stdin.write

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:966, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)
    963             self.stderr = io.TextIOWrapper(self.stderr,
    964                     encoding=encoding, errors=errors)
--> 966     self._execute_child(args, executable, preexec_fn, close_fds,
    967                         pass_fds, cwd, env,
    968                         startupinfo, creationflags, shell,
    969                         p2cread, p2cwrite,
    970                         c2pread, c2pwrite,
    971                         errread, errwrite,
    972                         restore_signals,
    973                         gid, gids, uid, umask,
    974                         start_new_session)
    975 except:
    976     # Cleanup if the child failed starting.

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:1842, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1841         err_msg = os.strerror(errno_num)
-> 1842     raise child_exception_type(errno_num, err_msg, err_filename)
   1843 raise child_exception_type(err_msg)

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/IPython/core/formatters.py:973, in MimeBundleFormatter.__call__(self, obj, include, exclude)
    970     method = get_real_method(obj, self.print_method)
    972     if method is not None:
--> 973         return method(include=include, exclude=exclude)
    974     return None
    975 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in <dictcomp>(.0)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
    110 def _repr_image_svg_xml(self) -> str:
    111     """Return the rendered graph as SVG string."""
--> 112     return self.pipe(format='svg', encoding=SVG_ENCODING)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)
     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)
    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=2)
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)
    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    146 if encoding is not None:
    147     if codecs.lookup(encoding) is codecs.lookup(self.encoding):
    148         # common case: both stdin and stdout need the same encoding
--> 149         return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
    150     try:
    151         raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
    206 cmd = dot_command.command(engine, format,
    207                           renderer=renderer,
    208                           formatter=formatter,
    209                           neato_no_op=neato_no_op)
    210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    213 return proc.stdout

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:84, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:
---> 84         raise ExecutableNotFound(cmd) from e
     85     raise
     87 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<graphviz.sources.Source at 0x7f9cd4a199f0>

(표현4)

- 위의 모델은 아래와 같이 쓸 수 있다. ($\beta_0$를 바이어스로 표현)

gv('''
"x" -> "x*β̂₁,    bias=True"[label="*β̂₁"] ;
"x*β̂₁,    bias=True" -> "ŷ"[label="indentity"] ''')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:79, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     78         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 79     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:99, in _run_input_lines(cmd, input_lines, kwargs)
     98 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 99     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
    101     stdin_write = popen.stdin.write

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:966, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)
    963             self.stderr = io.TextIOWrapper(self.stderr,
    964                     encoding=encoding, errors=errors)
--> 966     self._execute_child(args, executable, preexec_fn, close_fds,
    967                         pass_fds, cwd, env,
    968                         startupinfo, creationflags, shell,
    969                         p2cread, p2cwrite,
    970                         c2pread, c2pwrite,
    971                         errread, errwrite,
    972                         restore_signals,
    973                         gid, gids, uid, umask,
    974                         start_new_session)
    975 except:
    976     # Cleanup if the child failed starting.

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:1842, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1841         err_msg = os.strerror(errno_num)
-> 1842     raise child_exception_type(errno_num, err_msg, err_filename)
   1843 raise child_exception_type(err_msg)

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/IPython/core/formatters.py:973, in MimeBundleFormatter.__call__(self, obj, include, exclude)
    970     method = get_real_method(obj, self.print_method)
    972     if method is not None:
--> 973         return method(include=include, exclude=exclude)
    974     return None
    975 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in <dictcomp>(.0)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
    110 def _repr_image_svg_xml(self) -> str:
    111     """Return the rendered graph as SVG string."""
--> 112     return self.pipe(format='svg', encoding=SVG_ENCODING)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)
     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)
    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=2)
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)
    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    146 if encoding is not None:
    147     if codecs.lookup(encoding) is codecs.lookup(self.encoding):
    148         # common case: both stdin and stdout need the same encoding
--> 149         return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
    150     try:
    151         raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
    206 cmd = dot_command.command(engine, format,
    207                           renderer=renderer,
    208                           formatter=formatter,
    209                           neato_no_op=neato_no_op)
    210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    213 return proc.stdout

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:84, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:
---> 84         raise ExecutableNotFound(cmd) from e
     85     raise
     87 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<graphviz.sources.Source at 0x7f9cd487dab0>
  • 실제로는 이 표현을 많이 사용함

(표현5)

- 벡터버전으로 표현하면 아래와 같다. 이 경우에는 ${\bf X}=[1,x]$에 포함된 1이 bias의 역할을 해주므로 bias = False 임.

gv('''
"X" -> "X@β̂,    bias=False"[label="@β̂"] ;
"X@β̂,    bias=False" -> "ŷ"[label="indentity"] ''')
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:79, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     78         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 79     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:99, in _run_input_lines(cmd, input_lines, kwargs)
     98 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 99     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
    101     stdin_write = popen.stdin.write

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:966, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)
    963             self.stderr = io.TextIOWrapper(self.stderr,
    964                     encoding=encoding, errors=errors)
--> 966     self._execute_child(args, executable, preexec_fn, close_fds,
    967                         pass_fds, cwd, env,
    968                         startupinfo, creationflags, shell,
    969                         p2cread, p2cwrite,
    970                         c2pread, c2pwrite,
    971                         errread, errwrite,
    972                         restore_signals,
    973                         gid, gids, uid, umask,
    974                         start_new_session)
    975 except:
    976     # Cleanup if the child failed starting.

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:1842, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1841         err_msg = os.strerror(errno_num)
-> 1842     raise child_exception_type(errno_num, err_msg, err_filename)
   1843 raise child_exception_type(err_msg)

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/IPython/core/formatters.py:973, in MimeBundleFormatter.__call__(self, obj, include, exclude)
    970     method = get_real_method(obj, self.print_method)
    972     if method is not None:
--> 973         return method(include=include, exclude=exclude)
    974     return None
    975 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in <dictcomp>(.0)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
    110 def _repr_image_svg_xml(self) -> str:
    111     """Return the rendered graph as SVG string."""
--> 112     return self.pipe(format='svg', encoding=SVG_ENCODING)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)
     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)
    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=2)
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)
    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    146 if encoding is not None:
    147     if codecs.lookup(encoding) is codecs.lookup(self.encoding):
    148         # common case: both stdin and stdout need the same encoding
--> 149         return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
    150     try:
    151         raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
    206 cmd = dot_command.command(engine, format,
    207                           renderer=renderer,
    208                           formatter=formatter,
    209                           neato_no_op=neato_no_op)
    210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    213 return proc.stdout

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:84, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:
---> 84         raise ExecutableNotFound(cmd) from e
     85     raise
     87 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<graphviz.sources.Source at 0x7f9cd4885270>
  • 저는 이걸 좋아해요

(표현5)'

- 딥러닝에서는 $\hat{\boldsymbol{\beta}}$ 대신에 $\hat$을 라고 표현한다.

gv('''
"X" -> "X@Ŵ,    bias=False"[label="@Ŵ"] ;
"X@Ŵ,    bias=False" -> "ŷ"[label="identity"] ''')

---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:79, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     78         kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 79     proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
     80 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:99, in _run_input_lines(cmd, input_lines, kwargs)
     98 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 99     popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
    101     stdin_write = popen.stdin.write

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:966, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)
    963             self.stderr = io.TextIOWrapper(self.stderr,
    964                     encoding=encoding, errors=errors)
--> 966     self._execute_child(args, executable, preexec_fn, close_fds,
    967                         pass_fds, cwd, env,
    968                         startupinfo, creationflags, shell,
    969                         p2cread, p2cwrite,
    970                         c2pread, c2pwrite,
    971                         errread, errwrite,
    972                         restore_signals,
    973                         gid, gids, uid, umask,
    974                         start_new_session)
    975 except:
    976     # Cleanup if the child failed starting.

File ~/anaconda3/envs/py310/lib/python3.10/subprocess.py:1842, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)
   1841         err_msg = os.strerror(errno_num)
-> 1842     raise child_exception_type(errno_num, err_msg, err_filename)
   1843 raise child_exception_type(err_msg)

FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')

The above exception was the direct cause of the following exception:

ExecutableNotFound                        Traceback (most recent call last)
File ~/anaconda3/envs/py310/lib/python3.10/site-packages/IPython/core/formatters.py:973, in MimeBundleFormatter.__call__(self, obj, include, exclude)
    970     method = get_real_method(obj, self.print_method)
    972     if method is not None:
--> 973         return method(include=include, exclude=exclude)
    974     return None
    975 else:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:98, in <dictcomp>(.0)
     96 include = set(include) if include is not None else {self._jupyter_mimetype}
     97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
     99         for mimetype, method_name in MIME_TYPES.items()
    100         if mimetype in include}

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
    110 def _repr_image_svg_xml(self) -> str:
    111     """Return the rendered graph as SVG string."""
--> 112     return self.pipe(format='svg', encoding=SVG_ENCODING)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
     55 def pipe(self,
     56          format: typing.Optional[str] = None,
     57          renderer: typing.Optional[str] = None,
   (...)
     61          engine: typing.Optional[str] = None,
     62          encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
     63     """Return the source piped through the Graphviz layout command.
     64 
     65     Args:
   (...)
    102         '<?xml version='
    103     """
--> 104     return self._pipe_legacy(format,
    105                              renderer=renderer,
    106                              formatter=formatter,
    107                              neato_no_op=neato_no_op,
    108                              quiet=quiet,
    109                              engine=engine,
    110                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/_tools.py:171, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
    162     wanted = ', '.join(f'{name}={value!r}'
    163                        for name, value in deprecated.items())
    164     warnings.warn(f'The signature of {func.__name__} will be reduced'
    165                   f' to {supported_number} positional args'
    166                   f' {list(supported)}: pass {wanted}'
    167                   ' as keyword arg(s)',
    168                   stacklevel=stacklevel,
    169                   category=category)
--> 171 return func(*args, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    112 @_tools.deprecate_positional_args(supported_number=2)
    113 def _pipe_legacy(self,
    114                  format: typing.Optional[str] = None,
   (...)
    119                  engine: typing.Optional[str] = None,
    120                  encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121     return self._pipe_future(format,
    122                              renderer=renderer,
    123                              formatter=formatter,
    124                              neato_no_op=neato_no_op,
    125                              quiet=quiet,
    126                              engine=engine,
    127                              encoding=encoding)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
    146 if encoding is not None:
    147     if codecs.lookup(encoding) is codecs.lookup(self.encoding):
    148         # common case: both stdin and stdout need the same encoding
--> 149         return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
    150     try:
    151         raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
    206 cmd = dot_command.command(engine, format,
    207                           renderer=renderer,
    208                           formatter=formatter,
    209                           neato_no_op=neato_no_op)
    210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
    213 return proc.stdout

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/graphviz/backend/execute.py:84, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
     82 except OSError as e:
     83     if e.errno == errno.ENOENT:
---> 84         raise ExecutableNotFound(cmd) from e
     85     raise
     87 if not quiet and proc.stderr:

ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
<graphviz.sources.Source at 0x7f9cd4751ff0>

- 실제로는 표현4 혹은 표현5를 외우면 된다.

Layer의 개념

- (표현4) 혹은 (표현5)의 그림은 레이어로 설명할 수 있다.

- 레이어는 항상 아래와 같은 규칙을 가진다.

  • 첫 동그라미는 레이어의 입력이다.
  • 첫번째 화살표는 선형변환을 의미한다.
  • 두번째 동그라미는 선형변환의 결과이다. (이때 bias가 false인지 true인지에 따라서 실제 수식이 조금 다름)
  • 두번째 화살표는 두번째 동그라미에 어떠한 함수 $f$를 취하는 과정을 의미한다. (우리의 그림에서는 $f(x)=x$)
  • 세번째 동그라미는 레이어의 최종출력이다.

- 엄청 복잡한데, 결국 레이어를 만들때 위의 그림들을 의미하도록 하려면 아래의 4개의 요소만 필요하다.

  1. 레이어의 입력차원
  2. 선형변환의 결과로 얻어지는 차원
  3. 선형변환에서 바이어스를 쓸지? 안쓸지?
  4. 함수 $f$

- 주목: 1,2가 결정되면 자동으로 $\hat$의 차원이 결정된다.

(예시)

  • 레이어의 입력차원=2, 선형변환의 결과로 얻어지는 차원=1: $\hat{\bf W}$는 (2,1) 매트릭스
  • 레이어의 입력차원=20, 선형변환의 결과로 얻어지는 차원=5: $\hat{\bf W}$는 (20,5) 매트릭스
  • 레이어의 입력차원=2, 선형변환의 결과로 얻어지는 차원=50: $\hat{\bf W}$는 (2,50) 매트릭스

- 주목2: 이중에서 절대 생략불가능 것은 "2. 선형변환의 결과로 얻어지는 차원" 이다.

  • 레이어의 입력차원: 실제 레이어에 데이터가 들어올 때 데이터의 입력차원을 컴퓨터 스스로 체크하여 $\hat{\bf W}$의 차원을 결정할 수 있음.
  • 바이어스를 쓸지? 안쓸지? 기본적으로 쓴다고 가정한다.
  • 함수 $f$: 기본적으로 항등함수를 가정하면 된다.

Keras를 이용한 풀이

- 기본뼈대: net생성 $\to$ add(layer) $\to$ compile(opt,loss) $\to$ fit(data,epochs)

- 데이터정리

$${\bf y}\approx 2.5 +4*x$$

tnp.random.seed(43052)
N= 200 
x= tnp.linspace(0,1,N)
epsilon= tnp.random.randn(N)*0.5 
y= 2.5+4*x +epsilon
2022-04-18 13:26:23.084963: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:939] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
X=tf.stack([tf.ones(N,dtype='float64'),x],axis=1)

풀이1: 스칼라버전

(0단계) 데이터정리

y=y.reshape(N,1)
x=x.reshape(N,1)
x.shape,y.shape
(TensorShape([200, 1]), TensorShape([200, 1]))

(1단계) net 생성

net = tf.keras.Sequential() 

(2단계) net.add(layer)

layer = tf.keras.layers.Dense(1) 
net.add(layer)

(3단계) net.compile(opt,loss_fn)

net.compile(tf.keras.optimizers.SGD(0.1), tf.keras.losses.MSE) 

(4단계) net.fit(x,y,epochs)

net.fit(x,y,epochs=1000,verbose=0,batch_size=N) # batch_size=N 일 경우에 경사하강법이 적용, batch_size!=N 이면 확률적 경사하강법 적용
<keras.callbacks.History at 0x7f9cd3fc3af0>

(결과확인)

net.weights
[<tf.Variable 'dense/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[3.9330251]], dtype=float32)>,
 <tf.Variable 'dense/bias:0' shape=(1,) dtype=float32, numpy=array([2.5836723], dtype=float32)>]

풀이2: 벡터버전

(0단계) 데이터정리

X.shape,y.shape
(TensorShape([200, 2]), TensorShape([200, 1]))

(1단계) net 생성

net = tf.keras.Sequential() 

(2단계) net.add(layer)

layer = tf.keras.layers.Dense(1,use_bias=False) 
net.add(layer)

(3단계) net.compile(opt,loss_fn)

net.compile(tf.keras.optimizers.SGD(0.1), tf.keras.losses.MSE) 

(4단계) net.fit(x,y,epochs)

net.fit(X,y,epochs=1000,verbose=0,batch_size=N) # batch_size=N 일 경우에 경사하강법이 적용, batch_size!=N 이면 확률적 경사하강법 적용 
<keras.callbacks.History at 0x7f9c6426a2c0>

(결과확인)

net.weights
[<tf.Variable 'dense_1/kernel:0' shape=(2, 1) dtype=float32, numpy=
 array([[2.5836723],
        [3.9330251]], dtype=float32)>]

잠시문법정리

- 잠깐 Dense layer를 만드는 코드를 정리해보자.

(1) 아래는 모두 같은 코드이다.

  • tf.keras.layers.Dense(1)
  • tf.keras.layers.Dense(units=1)
  • tf.keras.layers.Dense(units=1,activation='linear') // identity 가 더 맞는것 같은데..
  • tf.keras.layers.Dense(units=1,activation='linear',use_bias=True)

(2) 아래의 코드1,2는 (1)의 코드들과 살짝 다른코드이다. (코드1과 코드2는 같은코드임)

  • tf.keras.layers.Dense(1,input_dim=2) # 코드1
  • tf.keras.layers.Dense(1,input_shape=(2,)) # 코드2

(3) 아래는 사용불가능한 코드이다.

  • tf.keras.layers.Dense(1,input_dim=(2,)) # 코드1
  • tf.keras.layers.Dense(1,input_shape=2) # 코드2

- 왜 input_dim이 필요한가?

net1 = tf.keras.Sequential()
net1.add(tf.keras.layers.Dense(1,use_bias=False)) 
net2 = tf.keras.Sequential()
net2.add(tf.keras.layers.Dense(1,use_bias=False,input_dim=2))
net1.weights
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [26], in <cell line: 1>()
----> 1 net1.weights

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/keras/engine/training.py:2542, in Model.weights(self)
   2532 @property
   2533 def weights(self):
   2534   """Returns the list of all layer variables/weights.
   2535 
   2536   Note: This will not track the weights of nested `tf.Modules` that are not
   (...)
   2540     A list of variables.
   2541   """
-> 2542   return self._dedup_weights(self._undeduplicated_weights)

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/keras/engine/training.py:2547, in Model._undeduplicated_weights(self)
   2544 @property
   2545 def _undeduplicated_weights(self):
   2546   """Returns the undeduplicated list of all layer variables/weights."""
-> 2547   self._assert_weights_created()
   2548   weights = []
   2549   for layer in self._self_tracked_trackables:

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/keras/engine/sequential.py:471, in Sequential._assert_weights_created(self)
    468   return
    469 # When the graph has not been initialized, use the Model's implementation to
    470 # to check if the weights has been created.
--> 471 super(functional.Functional, self)._assert_weights_created()

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/keras/engine/training.py:2736, in Model._assert_weights_created(self)
   2728   return
   2730 if ('build' in self.__class__.__dict__ and
   2731     self.__class__ != Model and
   2732     not self.built):
   2733   # For any model that has customized build() method but hasn't
   2734   # been invoked yet, this will cover both sequential and subclass model.
   2735   # Also make sure to exclude Model class itself which has build() defined.
-> 2736   raise ValueError(f'Weights for model {self.name} have not yet been '
   2737                    'created. '
   2738                    'Weights are created when the Model is first called on '
   2739                    'inputs or `build()` is called with an `input_shape`.')

ValueError: Weights for model sequential_2 have not yet been created. Weights are created when the Model is first called on inputs or `build()` is called with an `input_shape`.
net2.weights
[<tf.Variable 'dense_3/kernel:0' shape=(2, 1) dtype=float32, numpy=
 array([[-1.053657 ],
        [ 1.3536845]], dtype=float32)>]
net1.summary()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [28], in <cell line: 1>()
----> 1 net1.summary()

File ~/anaconda3/envs/py310/lib/python3.10/site-packages/keras/engine/training.py:2579, in Model.summary(self, line_length, positions, print_fn, expand_nested)
   2559 """Prints a string summary of the network.
   2560 
   2561 Args:
   (...)
   2576     ValueError: if `summary()` is called before the model is built.
   2577 """
   2578 if not self.built:
-> 2579   raise ValueError(
   2580       'This model has not yet been built. '
   2581       'Build the model first by calling `build()` or by calling '
   2582       'the model on a batch of data.')
   2583 layer_utils.print_summary(
   2584     self,
   2585     line_length=line_length,
   2586     positions=positions,
   2587     print_fn=print_fn,
   2588     expand_nested=expand_nested)

ValueError: This model has not yet been built. Build the model first by calling `build()` or by calling the model on a batch of data.
net2.summary()
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_3 (Dense)             (None, 1)                 2         
                                                                 
=================================================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
_________________________________________________________________

풀이3: 스칼라버전, 임의의 초기값을 설정

(0단계) 데이터정리

y=y.reshape(N,1)
x=x.reshape(N,1)
x.shape,y.shape
(TensorShape([200, 1]), TensorShape([200, 1]))

(1단계) net생성

net = tf.keras.Sequential() 

(2단계) net.add(layer)

layer = tf.keras.layers.Dense(1,input_dim=1)
net.add(layer)

초기값을 설정

net.weights
[<tf.Variable 'dense_4/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[0.534932]], dtype=float32)>,
 <tf.Variable 'dense_4/bias:0' shape=(1,) dtype=float32, numpy=array([0.], dtype=float32)>]
net.get_weights()
[array([[0.534932]], dtype=float32), array([0.], dtype=float32)]
  • weight, bias순으로 출력
net.set_weights?
Signature: net.set_weights(weights)
Docstring:
Sets the weights of the layer, from NumPy arrays.

The weights of a layer represent the state of the layer. This function
sets the weight values from numpy arrays. The weight values should be
passed in the order they are created by the layer. Note that the layer's
weights must be instantiated before calling this function, by calling
the layer.

For example, a `Dense` layer returns a list of two values: the kernel matrix
and the bias vector. These can be used to set the weights of another
`Dense` layer:

>>> layer_a = tf.keras.layers.Dense(1,
...   kernel_initializer=tf.constant_initializer(1.))
>>> a_out = layer_a(tf.convert_to_tensor([[1., 2., 3.]]))
>>> layer_a.get_weights()
[array([[1.],
       [1.],
       [1.]], dtype=float32), array([0.], dtype=float32)]
>>> layer_b = tf.keras.layers.Dense(1,
...   kernel_initializer=tf.constant_initializer(2.))
>>> b_out = layer_b(tf.convert_to_tensor([[10., 20., 30.]]))
>>> layer_b.get_weights()
[array([[2.],
       [2.],
       [2.]], dtype=float32), array([0.], dtype=float32)]
>>> layer_b.set_weights(layer_a.get_weights())
>>> layer_b.get_weights()
[array([[1.],
       [1.],
       [1.]], dtype=float32), array([0.], dtype=float32)]

Args:
  weights: a list of NumPy arrays. The number
    of arrays and their shape must match
    number of the dimensions of the weights
    of the layer (i.e. it should match the
    output of `get_weights`).

Raises:
  ValueError: If the provided weights list does not match the
    layer's specifications.
File:      ~/anaconda3/envs/py310/lib/python3.10/site-packages/keras/engine/base_layer.py
Type:      method
  • layer_b.set_weights(layer_a.get_weights()) 와 같은방식으로 쓴다는 것이군?

- 한번따라해보자.

_w = net.get_weights()
_w
[array([[0.534932]], dtype=float32), array([0.], dtype=float32)]
  • 길이가 2인 리스트이고, 각 원소는 numpy array 임
net.set_weights(
    [np.array([[10.0]],dtype=np.float32), # weight, β1_hat
     np.array([-5.0],dtype=np.float32)] # bias, β0_hat 
)
net.weights
[<tf.Variable 'dense_4/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[10.]], dtype=float32)>,
 <tf.Variable 'dense_4/bias:0' shape=(1,) dtype=float32, numpy=array([-5.], dtype=float32)>]

(3단계) net.compile()

net.compile(tf.keras.optimizers.SGD(0.1),tf.losses.MSE) 

(4단계) net.fit()

net.fit(x,y,epochs=1000,verbose=0,batch_size=N) 
<keras.callbacks.History at 0x7f9c642f0d30>

결과확인

net.weights
[<tf.Variable 'dense_4/kernel:0' shape=(1, 1) dtype=float32, numpy=array([[3.933048]], dtype=float32)>,
 <tf.Variable 'dense_4/bias:0' shape=(1,) dtype=float32, numpy=array([2.58366], dtype=float32)>]

풀이4: 벡터버전, 임의의 초기값을 설정

(0단계) 데이터정리

X.shape, y.shape
(TensorShape([200, 2]), TensorShape([200, 1]))

(1단계) net생성

net = tf.keras.Sequential()

(2단계) net.add(layer)

layer = tf.keras.layers.Dense(1,use_bias=False,input_dim=2) 
net.add(layer)

초기값을 설정하자

net.set_weights([np.array([[ -5.0],[10.0]], dtype=np.float32)])
net.get_weights()
[array([[-5.],
        [10.]], dtype=float32)]

(3단계) net.compile()

net.compile(tf.keras.optimizers.SGD(0.1), tf.losses.MSE) 

(4단계) net.fit()

net.fit(X,y,epochs=1000,verbose=0,batch_size=N) 
<keras.callbacks.History at 0x7f9c284f2ce0>
net.weights
[<tf.Variable 'dense_5/kernel:0' shape=(2, 1) dtype=float32, numpy=
 array([[2.58366 ],
        [3.933048]], dtype=float32)>]

- 사실 실전에서는 초기값을 설정할 필요가 별로 없음.

풀이5: 벡터버전 사용자정의 손실함수

(0단계) 데이터정리

X.shape, y.shape
(TensorShape([200, 2]), TensorShape([200, 1]))

(1단계) net생성

net = tf.keras.Sequential()

(2단계) net.add(layer)

layer = tf.keras.layers.Dense(1,use_bias=False) 
net.add(layer)

(3단계) net.compile()

loss_fn = lambda y,yhat: (y-yhat).T @ (y-yhat) / N
net.compile(tf.keras.optimizers.SGD(0.1), loss_fn) 

(4단계) net.fit()

net.fit(X,y,epochs=1000,verbose=0,batch_size=N) 
<keras.callbacks.History at 0x7f9c28350d90>
net.weights
[<tf.Variable 'dense_6/kernel:0' shape=(2, 1) dtype=float32, numpy=
 array([[2.5836723],
        [3.9330251]], dtype=float32)>]

풀이6: 벡터버전, net.compile의 옵션으로 손실함수 지정

(0단계) 데이터정리

X.shape, y.shape
(TensorShape([200, 2]), TensorShape([200, 1]))

(1단계) net생성

net = tf.keras.Sequential()

(2단계) net.add(layer)

net.add(tf.keras.layers.Dense(1,use_bias=False))

(3단계) net.compile()

net.compile(tf.keras.optimizers.SGD(0.1), loss='mse') 

(4단계) net.fit()

net.fit(X,y,epochs=1000,verbose=0,batch_size=N) 
<keras.callbacks.History at 0x7f9c2831eb90>
net.weights
[<tf.Variable 'dense_7/kernel:0' shape=(2, 1) dtype=float32, numpy=
 array([[2.5836723],
        [3.9330251]], dtype=float32)>]

풀이7: 벡터버전, net.compile의 옵션으로 손실함수 지정 + 옵티마이저 지정

(0단계) 데이터정리

X.shape, y.shape
(TensorShape([200, 2]), TensorShape([200, 1]))

(1단계) net생성

net = tf.keras.Sequential()

(2단계) net.add(layer)

net.add(tf.keras.layers.Dense(1,use_bias=False))

(3단계) net.compile()

net.compile(optimizer='sgd', loss='mse') 
#net.optimizer.lr = tf.Variable(0.1,dtype=tf.float32)
#net.optimizer.lr = 0.1

(4단계) net.fit()

net.fit(X,y,epochs=5000,verbose=0,batch_size=N) 
<keras.callbacks.History at 0x7f9c28244b20>
net.weights
[<tf.Variable 'dense_8/kernel:0' shape=(2, 1) dtype=float32, numpy=
 array([[2.5842712],
        [3.9319096]], dtype=float32)>]

여러가지 회귀모형의 적합과 학습과정의 모니터링

예제1

model: $y_i \approx \beta_0 +\beta_1 x_i$

np.random.seed(43052) 
N= 100 
x= np.random.randn(N) 
epsilon = np.random.randn(N)*0.5 
y= 2.5+4*x +epsilon
X= np.stack([np.ones(N),x],axis=1)
y= y.reshape(N,1)
plt.plot(x,y,'o') # 관측한 자료 
[<matplotlib.lines.Line2D at 0x7f9c2829e230>]
beta_hat = np.array([-3,-2]).reshape(2,1)
yhat = X@beta_hat 
plt.plot(x,y,'o')
plt.plot(x,yhat.reshape(-1),'-') 
[<matplotlib.lines.Line2D at 0x7f9c1870cb20>]

더 좋은 적합선을 얻기위해서!

slope = (2*X.T@X@beta_hat - 2*X.T@y)/ N 
beta_hat2 = beta_hat - 0.1*slope  
yhat2 = X@beta_hat2
plt.plot(x,y,'o')
plt.plot(x,yhat.reshape(-1),'-') 
plt.plot(x,yhat2.reshape(-1),'-') 
[<matplotlib.lines.Line2D at 0x7f9c284d9360>]

초록색이 좀 더 나아보인다.

beta_hat = np.array([-3,-2]).reshape(2,1) 
beta_hats = beta_hat # beta_hats = beta_hat.copy() 가 더 안전한 코드입니다. 
for i in range(1,30):
    yhat = X@beta_hat 
    slope = (2*X.T@X@beta_hat - 2*X.T@y) / N 
    beta_hat = beta_hat - 1.0*slope # 0.1은 적당, 0.3은 쪼금빠르지만 그래도 적당, 0.9는 너무 나간것같음, 1.0 은 수렴안함, 1.2 
    beta_hats = np.concatenate([beta_hats,beta_hat],axis=1) 
beta_hats
array([[-3.        ,  7.12238255, -1.2575366 ,  5.73166742, -0.1555309 ,
         4.86767499,  0.51106397,  4.36611576,  0.87316777,  4.12348617,
         1.01165173,  4.07771926,  0.97282343,  4.19586617,  0.77814101,
         4.46653491,  0.4299822 ,  4.89562729, -0.08537358,  5.50446319,
        -0.79684366,  6.32975688, -1.74933031,  7.42517729, -3.00603683,
         8.86442507, -4.6523303 , 10.74592463, -6.80132547, 13.19938129],
       [-2.        ,  8.70824998,  0.16165717,  6.93399596,  1.62435964,
         5.72089586,  2.63858056,  4.86387722,  3.37280529,  4.22385379,
         3.94259478,  3.70397678,  4.43004465,  3.23363047,  4.89701606,
         2.75741782,  5.39439054,  2.22728903,  5.96886945,  1.59655409,
         6.66836857,  0.81489407,  7.54676324, -0.17628423,  8.66856437,
        -1.44867655, 10.11401544, -3.09256176, 11.98507323, -5.22340389]])
b0hats = beta_hats[0].tolist()
b1hats = beta_hats[1].tolist()
np.linalg.inv(X.T@X) @ X.T @ y
array([[2.5451404 ],
       [3.94818596]])
from matplotlib import animation 
plt.rcParams["animation.html"] = "jshtml" 
fig = plt.figure(); fig.set_figheight(5); fig.set_figwidth(12)
<Figure size 864x360 with 0 Axes>
ax1= fig.add_subplot(1,2,1)
ax2= fig.add_subplot(1,2,2,projection='3d')
# ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,b0hats[0] + b1hats[0]*x) 
# ax2: 오른쪽그림 
β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij')
β0=β0.reshape(-1)
β1=β1.reshape(-1)
loss_fn = lambda b0,b1: np.sum((y-b0-b1*x)**2)
loss = list(map(loss_fn, β0,β1))
ax2.scatter(β0,β1,loss,alpha=0.02) 
ax2.scatter(2.5451404,3.94818596,loss_fn(2.5451404,3.94818596),s=200,marker='*') 

def animate(i):
    line.set_ydata(b0hats[i] + b1hats[i]*x) 
    ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey") 

ani = animation.FuncAnimation(fig,animate,frames=30) 
ani
</input>

예제2

model: $y_i \approx \beta_0 +\beta_1 e^{-x_i}$

np.random.seed(43052) 
N= 100 
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5 
y= 2.5+4*np.exp(-x) +epsilon
plt.plot(x,y,'o')
[<matplotlib.lines.Line2D at 0x7f9c184ef700>]
X= np.stack([np.ones(N),np.exp(-x)],axis=1)
y= y.reshape(N,1)
beta_hat = np.array([-3,-2]).reshape(2,1)
beta_hats = beta_hat.copy() # shallow copy, deep copy <--- 여름 방학 특강 
for i in range(1,30): 
    yhat = X@beta_hat 
    slope = (2*X.T@X@beta_hat - 2*X.T@y) /N 
    beta_hat = beta_hat - 0.05*slope 
    beta_hats = np.concatenate([beta_hats,beta_hat],axis=1) 
beta_hats
array([[-3.        , -1.74671631, -0.82428979, -0.14453919,  0.35720029,
         0.72834869,  1.0036803 ,  1.20869624,  1.36209751,  1.47759851,
         1.56525696,  1.63244908,  1.68458472,  1.72563174,  1.75850062,
         1.78532638,  1.80767543,  1.82669717,  1.84323521,  1.85790889,
         1.8711731 ,  1.88336212,  1.89472176,  1.90543297,  1.91562909,
         1.92540859,  1.93484428,  1.94399023,  1.9528867 ,  1.96156382],
       [-2.        , -0.25663415,  1.01939241,  1.95275596,  2.63488171,
         3.13281171,  3.49570765,  3.75961951,  3.95098231,  4.08918044,
         4.18842797,  4.2591476 ,  4.30898175,  4.34353413,  4.36691339,
         4.38213187,  4.39139801,  4.39633075,  4.39811673,  4.3976256 ,
         4.3954946 ,  4.3921905 ,  4.38805511,  4.3833386 ,  4.37822393,
         4.37284482,  4.36729887,  4.36165718,  4.35597148,  4.35027923]])
b0hats= beta_hats[0].tolist()
b1hats= beta_hats[1].tolist()
np.linalg.inv(X.T@X)@X.T@y
array([[2.46307644],
       [3.99681332]])
fig = plt.figure(); fig.set_figheight(5); fig.set_figwidth(12)
<Figure size 864x360 with 0 Axes>
ax1= fig.add_subplot(1,2,1)
ax2= fig.add_subplot(1,2,2,projection='3d')
# ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,b0hats[0] + b1hats[0]*np.exp(-x))
# ax2: 오른쪽그림 
β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij')
β0=β0.reshape(-1)
β1=β1.reshape(-1)
loss_fn = lambda b0,b1: np.sum((y-b0-b1*np.exp(-x))**2)
loss = list(map(loss_fn, β0,β1))
ax2.scatter(β0,β1,loss,alpha=0.02) 
ax2.scatter(2.46307644,3.99681332,loss_fn(2.46307644,3.99681332),s=200,marker='*') 

def animate(i):
    line.set_ydata(b0hats[i] + b1hats[i]*np.exp(-x))
    ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey") 

ani = animation.FuncAnimation(fig,animate,frames=30) 
ani
</input>

예제3

model: $y_i \approx \beta_0 +\beta_1 e^{-x_i} + \beta_2 \cos(5x_i)$

np.random.seed(43052) 
N= 100 
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5 
y= 2.5+4*np.exp(-x) + 5*np.cos(5*x) + epsilon
plt.plot(x,y,'o')
[<matplotlib.lines.Line2D at 0x7f9c1813e950>]
X=np.stack([np.ones(N),np.exp(-x),np.cos(5*x)],axis=1) 
y=y.reshape(N,1)
beta_hat = np.array([-3,-2,-1]).reshape(3,1) 
beta_hats = beta_hat.copy()
for i in range(1,30):
    yhat = X@beta_hat 
    slope = (2*X.T@X@beta_hat -2*X.T@y) /N 
    beta_hat = beta_hat - 0.1 * slope 
    beta_hats= np.concatenate([beta_hats,beta_hat],axis=1)
beta_hats
array([[-3.        , -0.71767532,  0.36255782,  0.89072137,  1.16423101,
         1.31925078,  1.41819551,  1.48974454,  1.54713983,  1.59655416,
         1.64091846,  1.68167278,  1.71956758,  1.75503084,  1.78833646,
         1.81968188,  1.84922398,  1.877096  ,  1.90341567,  1.92828934,
         1.95181415,  1.97407943,  1.99516755,  2.01515463,  2.0341111 ,
         2.05210214,  2.06918818,  2.08542523,  2.10086524,  2.11555643],
       [-2.        ,  1.16947474,  2.64116513,  3.33411605,  3.66880042,
         3.83768856,  3.92897389,  3.98315095,  4.01888831,  4.04486085,
         4.06516144,  4.08177665,  4.09571971,  4.10754954,  4.1176088 ,
         4.12613352,  4.13330391,  4.13926816,  4.14415391,  4.14807403,
         4.15112966,  4.1534121 ,  4.15500404,  4.15598045,  4.15640936,
         4.15635249,  4.15586584,  4.15500014,  4.15380139,  4.1523112 ],
       [-1.        , -0.95492718, -0.66119313, -0.27681968,  0.12788212,
         0.52254445,  0.89491388,  1.24088224,  1.55993978,  1.85310654,
         2.12199631,  2.36839745,  2.59408948,  2.8007666 ,  2.99000967,
         3.16327964,  3.32192026,  3.46716468,  3.60014318,  3.72189116,
         3.83335689,  3.93540864,  4.02884144,  4.11438316,  4.19270026,
         4.26440288,  4.33004965,  4.39015202,  4.44517824,  4.49555703]])
b0hats,b1hats,b2hats = beta_hats
np.linalg.inv(X.T@X) @ X.T @ y
array([[2.46597526],
       [4.00095138],
       [5.04161877]])
fig = plt.figure(); fig.set_figheight(5); fig.set_figwidth(12)
<Figure size 864x360 with 0 Axes>
ax1= fig.add_subplot(1,2,1)
ax2= fig.add_subplot(1,2,2,projection='3d')
# ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,b0hats[0] + b1hats[0]*np.exp(-x) + b2hats[0]*np.cos(5*x))
# ax2: 오른쪽그림 
# β0,β1 = np.meshgrid(np.arange(-6,11,0.25),np.arange(-6,11,0.25),indexing='ij')
# β0=β0.reshape(-1)
# β1=β1.reshape(-1)
# loss_fn = lambda b0,b1: np.sum((y-b0-b1*np.exp(-x))**2)
# loss = list(map(loss_fn, β0,β1))
# ax2.scatter(β0,β1,loss,alpha=0.02) 
# ax2.scatter(2.46307644,3.99681332,loss_fn(2.46307644,3.99681332),s=200,marker='*') 

def animate(i):
    line.set_ydata(b0hats[i] + b1hats[i]*np.exp(-x) + b2hats[i]*np.cos(5*x))
    # ax2.scatter(b0hats[i],b1hats[i],loss_fn(b0hats[i],b1hats[i]),color="grey") 

ani = animation.FuncAnimation(fig,animate,frames=30) 
ani
</input>

예제3: 케라스로 해보자!

model: $y_i \approx \beta_0 +\beta_1 e^{-x_i} + \beta_2 \cos(5x_i)$

np.random.seed(43052) 
N= 100 
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5 
y= 2.5+4*np.exp(-x) + 5*np.cos(5*x) + epsilon
X=np.stack([np.ones(N),np.exp(-x),np.cos(5*x)],axis=1) 
y=y.reshape(N,1)
net = tf.keras.Sequential() # 1: 네트워크 생성
net.add(tf.keras.layers.Dense(1,use_bias=False)) # 2: add layer 
net.compile(tf.optimizers.SGD(0.1), loss='mse') # 3: compile
net.fit(X,y,epochs=30, batch_size=N) # 4: fit 
Epoch 1/30
1/1 [==============================] - 0s 75ms/step - loss: 82.1027
Epoch 2/30
1/1 [==============================] - 0s 1ms/step - loss: 23.9512
Epoch 3/30
1/1 [==============================] - 0s 1ms/step - loss: 10.7256
Epoch 4/30
1/1 [==============================] - 0s 1ms/step - loss: 7.0664
Epoch 5/30
1/1 [==============================] - 0s 1ms/step - loss: 5.5521
Epoch 6/30
1/1 [==============================] - 0s 1ms/step - loss: 4.6075
Epoch 7/30
1/1 [==============================] - 0s 2ms/step - loss: 3.8836
Epoch 8/30
1/1 [==============================] - 0s 1ms/step - loss: 3.2909
Epoch 9/30
1/1 [==============================] - 0s 2ms/step - loss: 2.7971
Epoch 10/30
1/1 [==============================] - 0s 1ms/step - loss: 2.3838
Epoch 11/30
1/1 [==============================] - 0s 1ms/step - loss: 2.0374
Epoch 12/30
1/1 [==============================] - 0s 1ms/step - loss: 1.7471
Epoch 13/30
1/1 [==============================] - 0s 1ms/step - loss: 1.5038
Epoch 14/30
1/1 [==============================] - 0s 985us/step - loss: 1.2998
Epoch 15/30
1/1 [==============================] - 0s 1ms/step - loss: 1.1288
Epoch 16/30
1/1 [==============================] - 0s 1ms/step - loss: 0.9854
Epoch 17/30
1/1 [==============================] - 0s 1ms/step - loss: 0.8652
Epoch 18/30
1/1 [==============================] - 0s 1ms/step - loss: 0.7645
Epoch 19/30
1/1 [==============================] - 0s 1ms/step - loss: 0.6800
Epoch 20/30
1/1 [==============================] - 0s 1ms/step - loss: 0.6092
Epoch 21/30
1/1 [==============================] - 0s 1ms/step - loss: 0.5499
Epoch 22/30
1/1 [==============================] - 0s 1ms/step - loss: 0.5001
Epoch 23/30
1/1 [==============================] - 0s 1ms/step - loss: 0.4584
Epoch 24/30
1/1 [==============================] - 0s 1ms/step - loss: 0.4234
Epoch 25/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3941
Epoch 26/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3695
Epoch 27/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3489
Epoch 28/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3316
Epoch 29/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3171
Epoch 30/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3050
<keras.callbacks.History at 0x7f9c06753a60>
net.weights
[<tf.Variable 'dense_9/kernel:0' shape=(3, 1) dtype=float32, numpy=
 array([[2.4857023],
        [3.925291 ],
        [4.6923084]], dtype=float32)>]
plt.plot(x,y,'o') 
plt.plot(x,(X@net.weights).reshape(-1),'--')
[<matplotlib.lines.Line2D at 0x7f9c1818be50>]

숙제

예제2: 케라스를 이용하여 아래를 만족하는 적절한 $\beta_0$와 $\beta_1$을 구하라. 적합결과를 시각화하라. (애니메이션 시각화 X)

model: $y_i \approx \beta_0 +\beta_1 e^{-x_i}$

np.random.seed(43052) 
N= 100 
x= np.linspace(-1,1,N)
epsilon = np.random.randn(N)*0.5 
y= 2.5+4*np.exp(-x) +epsilon
X = np.stack([np.ones(N),np.exp(-x)],axis=1)
y = y.reshape(N,1)
net = tf.keras.Sequential() # 1: 네트워크 생성
net.add(tf.keras.layers.Dense(1,use_bias=False)) # 2: add layer 
net.compile(tf.optimizers.SGD(0.1), loss='mse') # 3: compile
net.fit(X,y,epochs=30, batch_size=N) # 4: fit 
Epoch 1/30
1/1 [==============================] - 0s 76ms/step - loss: 64.1211
Epoch 2/30
1/1 [==============================] - 0s 1ms/step - loss: 14.2919
Epoch 3/30
1/1 [==============================] - 0s 903us/step - loss: 3.4335
Epoch 4/30
1/1 [==============================] - 0s 910us/step - loss: 1.0607
Epoch 5/30
1/1 [==============================] - 0s 1ms/step - loss: 0.5360
Epoch 6/30
1/1 [==============================] - 0s 1ms/step - loss: 0.4142
Epoch 7/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3806
Epoch 8/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3667
Epoch 9/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3575
Epoch 10/30
1/1 [==============================] - 0s 2ms/step - loss: 0.3497
Epoch 11/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3427
Epoch 12/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3361
Epoch 13/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3300
Epoch 14/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3242
Epoch 15/30
1/1 [==============================] - 0s 991us/step - loss: 0.3189
Epoch 16/30
1/1 [==============================] - 0s 1ms/step - loss: 0.3139
Epoch 17/30
1/1 [==============================] - 0s 991us/step - loss: 0.3092
Epoch 18/30
1/1 [==============================] - 0s 980us/step - loss: 0.3048
Epoch 19/30
1/1 [==============================] - 0s 998us/step - loss: 0.3007
Epoch 20/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2969
Epoch 21/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2933
Epoch 22/30
1/1 [==============================] - 0s 946us/step - loss: 0.2900
Epoch 23/30
1/1 [==============================] - 0s 968us/step - loss: 0.2869
Epoch 24/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2840
Epoch 25/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2813
Epoch 26/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2787
Epoch 27/30
1/1 [==============================] - 0s 979us/step - loss: 0.2763
Epoch 28/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2741
Epoch 29/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2720
Epoch 30/30
1/1 [==============================] - 0s 1ms/step - loss: 0.2701
<keras.callbacks.History at 0x7f9c0665e590>