20221120일-밑러닝 준비, 팀미팅, 리트코드
대체로 토요일과 일요일 공부는 구분하지 않고 작성하는 것도 나쁘지 않은 듯. 시간에 얽매이질 않으니까.
미팅
레벨2 팀원들과의 첫 미팅! 성황리에 종료!
라고 쓰려니까 너무 아쉽네.. 태블릿으로 코딩을 하는 것에 한계를 느껴서 오랜만에 전설로만 존재할 뻔했던 내 노트북을 새삼 다시 꺼내서 가져갔다. 나름 조금 손을 대기는 했는데, 생각보다 안 깔린 것들이 너무 많고, 똥컴이라 그런지 느렸다.. 결국 원활하게 노트북을 활용하지 못했고, 그래서 제대로 메모를 할 수가 없다보니 다 정리하지는 못 했다. 이럴 거면 그냥 태블릿에 필기라도 할 걸. 그래도 메모장에 조금이라도 끄적인 것들은 있는데, 당장 여기에 옮겨 적기는 귀찮아서 보류한다.
모여서 이야기한 것은 일단 스터디를 어떻게 할 것인지. CS 관련 지식을 닦는 순서를 정했다. 데이터베이스와 네트워크를 합쳐서 이번 년도 안에 끝내기. 그리고 베이스라인 코드를 어떻게 현재 수정할 것이며 피쳐 엔지니어링을 어떻게 하면 되는지. 그리고 최종 프로젝트 아이디어 공유(이거를 빠짐 없이 전부 기록하고 싶었는데, 제대로 필기하지 못한 게 너무 아쉽다..).
2시간 가량의 미팅 이후 저녁을 함께 먹었다. 다음날 또 해야할 것이 있기 때문에 과음은 하지 않고 간단하게 한 병 정도. 집에 오니 정신이 엄청 말짱해져있어서 그냥 바로 공부했다.
밑러닝-11. 가변 길이 인수(순전파 편)
여태까지는 분기 없이 이어지는 역전파가 가능한 식들을 살펴봤다. 그러나 사실 더하기 같은 연산이 이뤄질 때는 분기가 일어날 수밖에 없다! 이런 것들이 가능해지도록 이번에는 가변 길이 입출력 처리를 해본다. forward든 backward든 두 가지 이상의 변수 객체가 들어올 수 있도록 처리를 해주는 것이다.
함수가 가변으로만 잘 받으면 그만이다! 그래서 복수로 들어올 수 있다고 손 치고 리스트로 받는 과정을 거친다. 이에 맞춰 당연히 출력도 리스트로 진행해준다.
그럼 간단하게 그렇게 인자를 받아서 계산을 하는 함수를 만들어보자. 아주 간단한 더하기 연산을 만들어봤다. 출력을 하기 위해 변수 객체로 묶을 때도 리스트 컴프리헨션을 쓰기에, iter 객체 모양으로 반환을 해야 한다..
사용하는 모습! 출력값이 리스트에 변수 객체를 담고 있는 모습을 확인할 수 있다. 그래서 인덱싱을 해서 변수 객체에 접근하여 데이터를 뽑아낸다.
밑러닝-12. 가변 길이 인수(개선 편)
위처럼 하는 방법은 좋지만, 귀찮은 측면이 없잖아 있다. 일단 입력을 할 때 필수적으로 iter객체로 묶게 만든다는 점. 그리고 하위 함수를 쓸 때 굳이 반환을 iter로 또 묶고 있다. 이런 점을 해결하는 게 진정한 가변 길이 인수라고 할 수 있다. 사실 위의 코드는 결국 iter 객체 하나를 가지고 내부에서 처리를 하는 것이기에 가변 길이 인수라고 보기에는.. 조금 어폐가 있는 것 같다. 아무튼 이를 해결해보자고.
첫번째 개선. 이제 입력할 때 굳이 iter로 안 묶어줘도 된다.
파이썬 매개변수에는 위치 가변 인자와, 키워드 가변 인자가 있다. 전자는 그냥 편하게 가변으로 전달하면 되고, 후자는 dict처럼 key, value를 합쳐서 전달해야만 한다. 이렇게 하면 args는 리스트로 묶이고, kwargs는 dict로 묶여서 함수 내부에서 사용되게 된다.
마음 같아서는 42에서 배웠던 printf와 연관을 짓고 싶은데, 시간이 부족해서 생략..
추가적으로 함수를 구현할 때 구태여 튜플에 묶는 작업을 하고 싶지 않기에, 이런 코드를 추가한다. 넣을 때도 알아서 풀려서 들어가도록 하고 내보내고 나서도 알아서 튜플로 묶어준다. 대신 튜플튜플이 되지 않도록 튜플이 아닐 때만 튜플로 묶는다!
이렇게 훨씬 더 사용하기 편하게 가변 인자를 받을 수 있게 됐다!
밑러닝-13. 가변 길이 인수(역전파 편)
이제까지 순전파를 했으니, 이제 역전파를 구현해보자.
간단한 아이디어. $y = x + z$라고 치면 이를 편미분하면 어떻게 되는가? x, z 전부 1이 나온다. 그래서 이전에 받은 값을 그대로 흘려보내주면 된다고 하는 것이다. 끽해봐야 1을 곱해서 보내주는 것밖에 더하기에서는 더 할 것이 없다.
그러나 이를 위해서 변수 객체의 역전파 코드가 많이 바뀐다. 주석으로 자세히 정리하면서 보았는데, 과정을 꽤나 많이 분할한다. 일단 y를 받는 과정은 간소화됐다. 원래는 y를 받은 이후 미분값에 접근하는데, 이번에는 처음부터 미분값으로 받아온다. 어차피 우리는 미분값만 쓰기에 상관 없긴 하다. 아무튼 그 이후에는 역전파 진행. 이것 역시 일단 튜플로 들어오도록 하게 하기 위해 역전파값을 받는 변수를 선언하여 사용한다. 그 이후에야 비로소 x의 미분값에 값을 저장해주는 것이다. 이를 통해 가변 길이를 전부 고려할 수 있고, 또한 분기가 나뉜 후에도 역전파가 각각에 대해 이뤄질 수 있도록 둘다 역전파를 진행할 함수 리스트에 넣어둔다.
음 마지막 예제를 따라 치려는데 문제가 발생했다.
무엇이 문제인가 했더니, input도 inputs라 해야 하는데 고치지 않아서 발생했던 문제. 당연히 입력으로 inputs가 들어오니 저장도 그리 해야하는데 처음에 오타 표시가 나지 않아서 제대로 작동하고 있는 줄 알았다.. 빠르게 찾아서 다행이다.
2의 제곱과 3의 세제곱은 31! 분기를 시켜서 각각의 미분값까지도 도출하는 모습을 확인할 수 있다!
밑러닝 발제 준비
1~7강 빠르게 복습. 저번에 나온 이야기 다시 한번 꺼내보기.
이후 8~13강.
컴퓨터를 통한 미분에는 세가지 방법이 있다. 수치 미분과, 도함수를 통한 미분, 그리고 자동 미분이다. 자동 미분은 사실 두 가지로 나뉘는데, 그 중 하나가 바로 역전파이다. 저번 주에 동영이가 연쇄 법칙의 식을 보면서 역전파의 순서와 정반대로 나아가는 미분이 가능하지 않을까 하는 이야기를 제시했고, 이번에 나는 그것을 정리했다. 실제로 역전파가 아닌, 입력에서부터 출발해 출력으로 나아가는 미분이 가능하다. 이 경우 변수 객체의 grad의 의미가 바뀌게 되고, 최종적인 미분값이 저장되는 위치도 바뀌게 된다.
간단하게 꼬리 재귀를 구현하는 모습. 그러나..재귀함수와 꼬리 재귀 (velog.io) 여기에 따르면 사실 파이썬은 꼬리 재귀가 알아서 지원되지는 않는다.
그렇다고 한다. 꼬리 재귀를 지원할 경우, 해당 컴파일러는 자동으로 꼬리 재귀를 반복문의 형태로 바꿔서 실행하며 그래서 반복문과 같은 동작을 하게 된다는 것. 코드를 알아보기 쉽고 변수를 적게 사용하는 재귀의 장점과, 메모리 할당이 적은 반복문의 이점을 같이 살릴 수 있게 된다.
변수 객체에 None을 넣는 경우가 있는가? 어떤 경우에 그러한가? 이것은 체크를 해두고 나중에 확인을 해봐야 할 것 같다.
10강 unittest 사용법. 만약 해당 파일에 들어있는 많은 테스트 클래스 중 하나만 쓰고 싶다면?
아예 해당 파일.테스트 이런 방식으로 해당 클래스만 테스트하는 것도 가능하다.
-v 옵션을 주면 더 상세한 테스트를 진행해준다. unittest를 활용할 것이라면 이 옵션은 필수이지 않을까.
discover를 통해 디렉이 있는 모든 test파일을 실행하는 것도 가능하다. 다만 파일 이름은 test로 시작해야만 한다!
unittest — 단위 테스트 프레임워크 — Python 3.11.0 문서 이 문서만 보더라도 unittest의 전반을 쉽게 다질 수 있다. 그러나 추가적으로 공부할 것이 많아보여서 일단은 생략. 만약 스터디 내에서 수요가 있다면 따로 더 공부해서 활용해보도록 하겠다.
스터디
본격적으로 스터디에 들어가기에 앞서 간단하게나마 성현이 형의 생일을 축하하기 위한 케이크를 사왔다. 처음 생각으로는 투썸의 케이크를 사는 방향이었으나, 내가 미리 답사한 바로는 생각보다 케이크의 크기가 커서 어느 정도는 식사를 하는 정도로 생각을 해야할 것 같았다. 그래서 바로 앞의 스벅에서 작은 종류의 케이크를 여러 개 사는 것으로 방향을 수정했다.
발제를 하는 입장에서 나온 이야기들을 다 필기할 여력이 부족했다. 뭔가 나설 때 꼭 정신이 없어져서 차분하게 정리하는 것에 많이 약해지곤 하는데, 이것도 많이 해봐야 느는 것이겠지.
원래는 42에서 내가 만들었던 C언어 printf까지 보여주면서 가변 길이 인자를 받는 방식, 그것이 메모리에 어떻게 들어가는지 보여주고 싶었으나.. 파이썬의 가변 길이 인자가 어떻게 메모리에 쌓이는지에 대한 글은 결국 찾아내지 못 했고, 또 생각보다 발표에 시간이 많이 소요되어 생략했다. 발표를 잘했는지에 대한 확신이 없는데, 일단 이런 것들에 익숙해지는 것이 정말 중요할 것 같다.
변수 객체는 데이터를 하나만 받아야 하는가? 최소한 함수를 통해 계산되어야 하는 두 데이터라면 그렇다. 각각의 미분값이 필요할 것이고, 함수의 원활한 작동을 위해 필요할 것이다. 다만 이후에 변수 객체를 선언하는 것을 더 편하게 하는 방법이 있을 수도 있으며 이는 추후 책에서 어떻게 개선되는지 살펴보면 좋을 것.
진도로 나가지는 않은 내용이지만, zero_grad의 작동 방식에 대한 이야기가 나왔다. 미분값을 0으로 만들어줘야 하는 이유는 그렇다치는데, 왜 따로 함수를 만들어야 하는가? 이후 성현이 형이 파이토치의 zero_grad 소스 코드를 뜯어보았는데 결국 이 함수 작동 자체는 정말 0으로 만드는 것에 중점이 맞춰져 있으며 들어온 자료형이나 설정에 대한 조치가 많이 이뤄진 것을 확인할 수 있었다. 다음 주에 나가게 될 내용에서 한번 더 다루면 좋을 듯하다.
그리고 또 유의미하게 나왔던 이야기가 있었던 것으로 기억하는데, 적어두지를 않아서 까먹었다.. 돌대가리야
스터디에 관하여 정한 사항. 앞으로 스터디는 매주 책 6단계씩, 그리고 파이토치 2레벨씩 진행한다. 나아가는 내용이 늘어남에 따라 스터디 진행시간도 더 길어지게 될 것이다. 또한 한 명이 발제의 부담을 많이 지는 것을 덜기 위하여, 그리고 효율을 위하여 발제는 매주 4명이 한다. 남은 한 명은 서기를 하여 내용을 정리하는 식으로. 두 명이 책의 3단계씩 나누어 발제하고, 또 두 명이 파이토치 레벨 하나씩을 맡게 된다.
또한 깃헙을 만든다! 포크를 하는 방법과 콜라보를 하는 방법, 두 가지가 있는데 일단 현업에서 더 자주 쓰일 것으로 예상되는 스타일인 포크의 방식으로 하는 것으로 이야기가 되었다. 포크란? 외부의 저장소를 내 저장소에 끌어온다. 그럼 나는 자유롭게 내 저장소에서 뜯어고칠 수 있고, 이를 나중에 원작에 요청을 하여 반영할 수 있다.
그리고 READ.md를 활용해 자신이 맡은 부분을 간단하게 정리하면서 깃헙에 업로드를 하게 될 것.
해야할 내용이 많아서 부담이 되지 않을까 싶기는 하지만, 같이 하는 사람들이 있으니 더 열심히 해야겠지. 최소한 하는 만큼 얻는 것은 분명 있다!
Leetcode Weekly Contest
음. 우리 팀에서 진행하기로 한 코테 문제 풀기. 영어가 읽기 어려울 것이라 생각했는데 첫 문제는 그래도 나쁘지 않다.
class Solution:
def convertTemperature(self, celsius: float) -> List[float]:
kel = celsius + 273.15
far = celsius * 1.80 + 32.00
return (kel, far)
근데... 사실 맞은 건지 틀린 건지 잘 모르겠다! 빨간 글씨가 없으면 맞는 거겠지..
최소 공배수가 k가 되는 조합의 갯수를 구하기.
흠. 내가 이해를 잘못 하고 있는 것일까? 이게 이렇게 될 것이라면 위의 예시에서도 6, 1의 최소공배수로 6을 삼아야할 것 같은데.. 왜 1만 있을 때는 쳐주는 거지?
그리고 2,3의 최소공배수는 6이니까 이 경우도 따져야 하는 것 아닌가? 음. 이것은 정의에 따라 안 되기는 하는 듯. 이 문제는 해당 최소공배수가 집합 안에 있기를 바라고 있다.
겨우 내가 놓친 점을 알게 됐는데, 바로 연속적인 집합이어야 한다는 조건. 익숙치 않은 언어이다보니 얼추 의미 이해를 하게 되고, 그러다가 중요한 부분을 놓치게 된 것 같다.
from math import lcm
class Solution:
def subarrayLCM(self, nums: List[int], k: int) -> int:
ans = 0
for i in range(len(nums)):
l = nums[i]
for j in range(i, len(nums)):
l = lcm(l, nums[j])
if l == k: ans +=1
if l > k: break
return ans
처음에는 combinations도 쓰고 별 걸 다 쓰려 했는데, 오히려 제한 사항이 명확해지니 문제는 더 쉬워졌다. 근데 막히는 부분이었던 것이, 내 코드는 시간초과가 나더라는 것. 그러다 한번 discussion 들어가보니 있는 코드. 거의 비슷한데, 나는 lcm에 부분집합의 모든 원소들을 담은 반면 이 코드는 양쪽 끝단의 원소들만 넣는 모습이다. 그러고보면 중간에 l이 커지는 시점에 어차피 break가 걸릴 예정이기 때문에 상관 없는 것 같기도.
이 이후로는 내일 풀까 하여 보류!
회고 및 다짐
음. 영어로 문제를 푸는 것은 생각보다는 훨씬 더 어려웠다. 해보면 되겠다 싶었는데, 꽤 안 되더라! 앞으로 계속 하면서 익숙해져야만 할 것 같다. 그리고 리트코드의 문제는 간결하면서도 적당히 어려운 것 같다. 그러나 알고리즘에 더 빠삭하다면 쉽다고 느낄 수도 있을 문제들인 것 같다. 해보니까 나쁘지는 않다!
주말에 쉴 시간이 많이 없이 밖에 나가있었더니 조금 피로하다. 집이었으면 조금이라도 쉬었을 시간에 움직이다보니 그런 것 같기도 하고. 그래도 사람들과 어울리는 것은 좋다! 이렇게 에너지 얻고 다음 주도 더 열심히 해보자.
EDA와 피쳐 엔지니어링, 트랜스포머 구조 익히기. 이것들을 위주로 하면서 이후 미션들을 해나가는 것이 좋겠다.
스터디 공부로는 책 14~19, 라이트닝 1~2레벨. 여기에 CS 데이터베이스 읽기.
멘토님 숙제 공부도 해야 한다.
이것들은 앞으로 거의 고정된 일들이라 일상화가 되도록 해야만 한다. 적고나니 엄청 많은데, 실제로도 엄청 많긴 한 것 같다. 그래도 뭐 어쩌냐. 하나씩 해보다보면 조금씩 줄어드는 것이다. 이번 주가 그러했던 것처럼!